From c2eaacd30565604bbf776ca6e83c9889ea87ea74 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 17 Jan 2012 19:14:08 +0000 Subject: [PATCH] Add dwc_otg driver Signed-off-by: popcornmix --- drivers/usb/Makefile | 1 + drivers/usb/core/generic.c | 1 + drivers/usb/core/hub.c | 52 +- drivers/usb/core/message.c | 79 + drivers/usb/core/otg_whitelist.h | 172 +- drivers/usb/gadget/Kconfig | 28 + drivers/usb/gadget/file_storage.c | 70 +- drivers/usb/host/Kconfig | 13 + drivers/usb/host/Makefile | 2 + drivers/usb/host/dwc_common_port/Makefile | 44 + .../usb/host/dwc_common_port/Makefile.linux | 36 + .../usb/host/dwc_common_port/doc/doxygen.cfg | 270 + .../dir_c13d72e45af28cdc461a5f284d3d36fc.html | 81 + .../host/dwc_common_port/doc/html/dirs.html | 22 + .../host/dwc_common_port/doc/html/doxygen.css | 358 ++ .../dwc_common_port/doc/html/dwc__cc_8h.html | 709 +++ .../doc/html/dwc__crypto_8c.html | 435 ++ .../doc/html/dwc__crypto_8h.html | 618 ++ .../dwc_common_port/doc/html/dwc__dh_8h.html | 166 + .../doc/html/dwc__list_8h.html | 1844 ++++++ .../doc/html/dwc__modpow_8h.html | 48 + .../doc/html/dwc__notifier_8h.html | 306 + .../dwc_common_port/doc/html/dwc__os_8h.html | 3090 ++++++++++ .../host/dwc_common_port/doc/html/files.html | 34 + .../dwc_common_port/doc/html/globals.html | 163 + .../doc/html/globals_defs.html | 41 + .../doc/html/globals_func.html | 153 + .../doc/html/globals_type.html | 41 + .../host/dwc_common_port/doc/html/index.html | 8 + .../host/dwc_common_port/doc/html/main.html | 45 + .../host/dwc_common_port/doc/html/pages.html | 23 + .../host/dwc_common_port/doc/html/tabs.css | 102 + .../host/dwc_common_port/doc/html/todo.html | 23 + .../host/dwc_common_port/doc/html/tree.html | 90 + drivers/usb/host/dwc_common_port/dwc_cc.c | 506 ++ drivers/usb/host/dwc_common_port/dwc_cc.h | 209 + .../host/dwc_common_port/dwc_common_linux.c | 1247 ++++ drivers/usb/host/dwc_common_port/dwc_crypto.c | 306 + drivers/usb/host/dwc_common_port/dwc_crypto.h | 103 + drivers/usb/host/dwc_common_port/dwc_dh.c | 286 + drivers/usb/host/dwc_common_port/dwc_dh.h | 98 + drivers/usb/host/dwc_common_port/dwc_list.h | 616 ++ drivers/usb/host/dwc_common_port/dwc_mem.c | 172 + drivers/usb/host/dwc_common_port/dwc_modpow.c | 622 ++ drivers/usb/host/dwc_common_port/dwc_modpow.h | 26 + .../usb/host/dwc_common_port/dwc_notifier.c | 256 + .../usb/host/dwc_common_port/dwc_notifier.h | 112 + drivers/usb/host/dwc_common_port/dwc_os.h | 924 +++ drivers/usb/host/dwc_common_port/usb.h | 850 +++ drivers/usb/host/dwc_otg/Makefile | 78 + drivers/usb/host/dwc_otg/doc/doxygen.cfg | 224 + .../usb/host/dwc_otg/doc/html/annotated.html | 120 + drivers/usb/host/dwc_otg/doc/html/doxygen.css | 358 ++ .../doc/html/dummy__audio_8c-source.html | 1550 +++++ .../doc/html/dwc__cfi__common_8h-source.html | 115 + .../dwc_otg/doc/html/dwc__cfi__common_8h.html | 119 + .../doc/html/dwc__otg__attr_8c-source.html | 828 +++ .../dwc_otg/doc/html/dwc__otg__attr_8c.html | 485 ++ .../doc/html/dwc__otg__attr_8h-source.html | 105 + .../dwc_otg/doc/html/dwc__otg__attr_8h.html | 116 + .../doc/html/dwc__otg__cfi_8c-source.html | 1724 ++++++ .../dwc_otg/doc/html/dwc__otg__cfi_8c.html | 36 + .../doc/html/dwc__otg__cfi_8h-source.html | 299 + .../dwc_otg/doc/html/dwc__otg__cfi_8h.html | 302 + .../doc/html/dwc__otg__cil_8c-source.html | 4922 +++++++++++++++ .../dwc_otg/doc/html/dwc__otg__cil_8c.html | 3103 ++++++++++ .../doc/html/dwc__otg__cil_8h-source.html | 709 +++ .../dwc_otg/doc/html/dwc__otg__cil_8h.html | 1844 ++++++ .../html/dwc__otg__cil__intr_8c-source.html | 742 +++ .../doc/html/dwc__otg__cil__intr_8c.html | 645 ++ .../html/dwc__otg__core__if_8h-source.html | 365 ++ .../doc/html/dwc__otg__core__if_8h.html | 1730 ++++++ .../doc/html/dwc__otg__dbg_8h-source.html | 100 + .../dwc_otg/doc/html/dwc__otg__dbg_8h.html | 133 + .../doc/html/dwc__otg__driver_8c-source.html | 1079 ++++ .../dwc_otg/doc/html/dwc__otg__driver_8c.html | 719 +++ .../doc/html/dwc__otg__driver_8h-source.html | 110 + .../dwc_otg/doc/html/dwc__otg__driver_8h.html | 50 + .../doc/html/dwc__otg__hcd_8c-source.html | 2946 +++++++++ .../dwc_otg/doc/html/dwc__otg__hcd_8c.html | 1837 ++++++ .../doc/html/dwc__otg__hcd_8h-source.html | 517 ++ .../dwc_otg/doc/html/dwc__otg__hcd_8h.html | 1310 ++++ .../html/dwc__otg__hcd__ddma_8c-source.html | 1070 ++++ .../doc/html/dwc__otg__hcd__ddma_8c.html | 311 + .../doc/html/dwc__otg__hcd__if_8h-source.html | 191 + .../doc/html/dwc__otg__hcd__if_8h.html | 1381 +++++ .../html/dwc__otg__hcd__intr_8c-source.html | 1873 ++++++ .../doc/html/dwc__otg__hcd__intr_8c.html | 1252 ++++ .../html/dwc__otg__hcd__linux_8c-source.html | 726 +++ .../doc/html/dwc__otg__hcd__linux_8c.html | 514 ++ .../html/dwc__otg__hcd__queue_8c-source.html | 633 ++ .../doc/html/dwc__otg__hcd__queue_8c.html | 667 ++ .../doc/html/dwc__otg__pcd_8c-source.html | 1851 ++++++ .../dwc_otg/doc/html/dwc__otg__pcd_8c.html | 1343 ++++ .../doc/html/dwc__otg__pcd_8h-source.html | 171 + .../dwc_otg/doc/html/dwc__otg__pcd_8h.html | 254 + .../doc/html/dwc__otg__pcd__if_8h-source.html | 174 + .../doc/html/dwc__otg__pcd__if_8h.html | 976 +++ .../html/dwc__otg__pcd__intr_8c-source.html | 3629 +++++++++++ .../doc/html/dwc__otg__pcd__intr_8c.html | 1599 +++++ .../html/dwc__otg__pcd__linux_8c-source.html | 997 +++ .../doc/html/dwc__otg__pcd__linux_8c.html | 796 +++ .../doc/html/dwc__otg__regs_8h-source.html | 1260 ++++ .../dwc_otg/doc/html/dwc__otg__regs_8h.html | 1468 +++++ drivers/usb/host/dwc_otg/doc/html/files.html | 52 + .../usb/host/dwc_otg/doc/html/functions.html | 82 + .../host/dwc_otg/doc/html/functions_0x62.html | 99 + .../host/dwc_otg/doc/html/functions_0x63.html | 110 + .../host/dwc_otg/doc/html/functions_0x64.html | 158 + .../host/dwc_otg/doc/html/functions_0x65.html | 109 + .../host/dwc_otg/doc/html/functions_0x66.html | 81 + .../host/dwc_otg/doc/html/functions_0x67.html | 95 + .../host/dwc_otg/doc/html/functions_0x68.html | 119 + .../host/dwc_otg/doc/html/functions_0x69.html | 121 + .../host/dwc_otg/doc/html/functions_0x6c.html | 74 + .../host/dwc_otg/doc/html/functions_0x6d.html | 79 + .../host/dwc_otg/doc/html/functions_0x6e.html | 99 + .../host/dwc_otg/doc/html/functions_0x6f.html | 101 + .../host/dwc_otg/doc/html/functions_0x70.html | 144 + .../host/dwc_otg/doc/html/functions_0x71.html | 71 + .../host/dwc_otg/doc/html/functions_0x72.html | 141 + .../host/dwc_otg/doc/html/functions_0x73.html | 128 + .../host/dwc_otg/doc/html/functions_0x74.html | 88 + .../host/dwc_otg/doc/html/functions_0x75.html | 78 + .../host/dwc_otg/doc/html/functions_0x76.html | 65 + .../host/dwc_otg/doc/html/functions_0x77.html | 79 + .../host/dwc_otg/doc/html/functions_0x78.html | 77 + .../host/dwc_otg/doc/html/functions_func.html | 36 + .../host/dwc_otg/doc/html/functions_vars.html | 82 + .../dwc_otg/doc/html/functions_vars_0x62.html | 99 + .../dwc_otg/doc/html/functions_vars_0x63.html | 110 + .../dwc_otg/doc/html/functions_vars_0x64.html | 157 + .../dwc_otg/doc/html/functions_vars_0x65.html | 109 + .../dwc_otg/doc/html/functions_vars_0x66.html | 81 + .../dwc_otg/doc/html/functions_vars_0x67.html | 95 + .../dwc_otg/doc/html/functions_vars_0x68.html | 119 + .../dwc_otg/doc/html/functions_vars_0x69.html | 121 + .../dwc_otg/doc/html/functions_vars_0x6c.html | 74 + .../dwc_otg/doc/html/functions_vars_0x6d.html | 79 + .../dwc_otg/doc/html/functions_vars_0x6e.html | 99 + .../dwc_otg/doc/html/functions_vars_0x6f.html | 101 + .../dwc_otg/doc/html/functions_vars_0x70.html | 144 + .../dwc_otg/doc/html/functions_vars_0x71.html | 71 + .../dwc_otg/doc/html/functions_vars_0x72.html | 141 + .../dwc_otg/doc/html/functions_vars_0x73.html | 128 + .../dwc_otg/doc/html/functions_vars_0x74.html | 88 + .../dwc_otg/doc/html/functions_vars_0x75.html | 78 + .../dwc_otg/doc/html/functions_vars_0x76.html | 65 + .../dwc_otg/doc/html/functions_vars_0x77.html | 79 + .../dwc_otg/doc/html/functions_vars_0x78.html | 77 + .../usb/host/dwc_otg/doc/html/globals.html | 87 + .../host/dwc_otg/doc/html/globals_0x61.html | 76 + .../host/dwc_otg/doc/html/globals_0x62.html | 83 + .../host/dwc_otg/doc/html/globals_0x63.html | 100 + .../host/dwc_otg/doc/html/globals_0x64.html | 686 +++ .../host/dwc_otg/doc/html/globals_0x65.html | 78 + .../host/dwc_otg/doc/html/globals_0x66.html | 87 + .../host/dwc_otg/doc/html/globals_0x67.html | 93 + .../host/dwc_otg/doc/html/globals_0x68.html | 129 + .../host/dwc_otg/doc/html/globals_0x69.html | 76 + .../host/dwc_otg/doc/html/globals_0x6b.html | 69 + .../host/dwc_otg/doc/html/globals_0x6d.html | 84 + .../host/dwc_otg/doc/html/globals_0x6e.html | 68 + .../host/dwc_otg/doc/html/globals_0x6f.html | 73 + .../host/dwc_otg/doc/html/globals_0x70.html | 84 + .../host/dwc_otg/doc/html/globals_0x71.html | 70 + .../host/dwc_otg/doc/html/globals_0x72.html | 94 + .../host/dwc_otg/doc/html/globals_0x73.html | 85 + .../host/dwc_otg/doc/html/globals_0x74.html | 68 + .../host/dwc_otg/doc/html/globals_0x75.html | 80 + .../host/dwc_otg/doc/html/globals_0x76.html | 75 + .../host/dwc_otg/doc/html/globals_0x77.html | 74 + .../host/dwc_otg/doc/html/globals_defs.html | 68 + .../dwc_otg/doc/html/globals_defs_0x61.html | 64 + .../dwc_otg/doc/html/globals_defs_0x62.html | 71 + .../dwc_otg/doc/html/globals_defs_0x63.html | 74 + .../dwc_otg/doc/html/globals_defs_0x64.html | 241 + .../dwc_otg/doc/html/globals_defs_0x66.html | 71 + .../dwc_otg/doc/html/globals_defs_0x67.html | 62 + .../dwc_otg/doc/html/globals_defs_0x68.html | 63 + .../dwc_otg/doc/html/globals_defs_0x69.html | 62 + .../dwc_otg/doc/html/globals_defs_0x6d.html | 76 + .../dwc_otg/doc/html/globals_defs_0x6e.html | 62 + .../dwc_otg/doc/html/globals_defs_0x6f.html | 67 + .../dwc_otg/doc/html/globals_defs_0x72.html | 66 + .../dwc_otg/doc/html/globals_defs_0x73.html | 63 + .../dwc_otg/doc/html/globals_defs_0x75.html | 64 + .../dwc_otg/doc/html/globals_defs_0x76.html | 68 + .../host/dwc_otg/doc/html/globals_enum.html | 44 + .../host/dwc_otg/doc/html/globals_eval.html | 43 + .../host/dwc_otg/doc/html/globals_func.html | 77 + .../dwc_otg/doc/html/globals_func_0x61.html | 70 + .../dwc_otg/doc/html/globals_func_0x62.html | 68 + .../dwc_otg/doc/html/globals_func_0x63.html | 77 + .../dwc_otg/doc/html/globals_func_0x64.html | 427 ++ .../dwc_otg/doc/html/globals_func_0x65.html | 73 + .../dwc_otg/doc/html/globals_func_0x66.html | 72 + .../dwc_otg/doc/html/globals_func_0x67.html | 78 + .../dwc_otg/doc/html/globals_func_0x68.html | 101 + .../dwc_otg/doc/html/globals_func_0x69.html | 71 + .../dwc_otg/doc/html/globals_func_0x6b.html | 66 + .../dwc_otg/doc/html/globals_func_0x6d.html | 66 + .../dwc_otg/doc/html/globals_func_0x70.html | 78 + .../dwc_otg/doc/html/globals_func_0x71.html | 67 + .../dwc_otg/doc/html/globals_func_0x72.html | 80 + .../dwc_otg/doc/html/globals_func_0x73.html | 77 + .../dwc_otg/doc/html/globals_func_0x75.html | 73 + .../dwc_otg/doc/html/globals_func_0x76.html | 65 + .../dwc_otg/doc/html/globals_func_0x77.html | 70 + .../host/dwc_otg/doc/html/globals_type.html | 175 + .../host/dwc_otg/doc/html/globals_vars.html | 120 + drivers/usb/host/dwc_otg/doc/html/index.html | 8 + .../doc/html/linux module attributes.html | 130 + drivers/usb/host/dwc_otg/doc/html/main.html | 21 + .../dwc_otg/doc/html/module parameters.html | 189 + drivers/usb/host/dwc_otg/doc/html/pages.html | 27 + .../struct__ddma__align__buffer__setup.html | 46 + .../struct__ddma__concat__buffer__setup.html | 46 + ...uct__ddma__concat__buffer__setup__hdr.html | 49 + .../html/struct__ddma__sg__buffer__setup.html | 57 + .../html/struct__rx__fifo__size__setup.html | 43 + .../html/struct__tx__fifo__size__setup.html | 46 + .../structcfi__all__features__header.html | 75 + .../doc/html/structcfi__dma__buff.html | 41 + .../host/dwc_otg/doc/html/structcfi__ep.html | 69 + .../structcfi__feature__desc__header.html | 60 + .../host/dwc_otg/doc/html/structcfi__ops.html | 64 + .../dwc_otg/doc/html/structcfi__string.html | 48 + .../doc/html/structcfi__usb__ctrlrequest.html | 58 + .../dwc_otg/doc/html/structcfiobject.html | 62 + .../host/dwc_otg/doc/html/structdwc__ep.html | 192 + .../host/dwc_otg/doc/html/structdwc__hc.html | 345 ++ .../html/structdwc__otg__cil__callbacks.html | 70 + .../structdwc__otg__core__global__regs.html | 557 ++ .../doc/html/structdwc__otg__core__if.html | 190 + .../html/structdwc__otg__core__params.html | 606 ++ .../html/structdwc__otg__dev__dma__desc.html | 50 + .../structdwc__otg__dev__global__regs.html | 441 ++ .../doc/html/structdwc__otg__dev__if.html | 142 + .../structdwc__otg__dev__in__ep__regs.html | 221 + .../structdwc__otg__dev__out__ep__regs.html | 221 + .../doc/html/structdwc__otg__device.html | 64 + ...tructdwc__otg__driver__module__params.html | 146 + .../doc/html/structdwc__otg__hc__regs.html | 200 + .../dwc_otg/doc/html/structdwc__otg__hcd.html | 377 ++ .../structdwc__otg__hcd__function__ops.html | 53 + ...tructdwc__otg__hcd__iso__packet__desc.html | 47 + .../html/structdwc__otg__hcd__pipe__info.html | 50 + .../doc/html/structdwc__otg__hcd__urb.html | 80 + .../html/structdwc__otg__host__dma__desc.html | 50 + .../structdwc__otg__host__global__regs.html | 219 + .../doc/html/structdwc__otg__host__if.html | 66 + .../dwc_otg/doc/html/structdwc__otg__pcd.html | 152 + .../doc/html/structdwc__otg__pcd__ep.html | 77 + .../structdwc__otg__pcd__function__ops.html | 73 + .../html/structdwc__otg__pcd__request.html | 64 + .../dwc_otg/doc/html/structdwc__otg__qh.html | 228 + .../dwc_otg/doc/html/structdwc__otg__qtd.html | 157 + .../doc/html/structgadget__wrapper.html | 53 + .../doc/html/structiso__pkt__info.html | 49 + .../doc/html/structwrapper__priv__data.html | 38 + .../dwc_otg/doc/html/structzero__dev.html | 56 + drivers/usb/host/dwc_otg/doc/html/tabs.css | 102 + drivers/usb/host/dwc_otg/doc/html/todo.html | 262 + drivers/usb/host/dwc_otg/doc/html/tree.html | 201 + .../dwc_otg/doc/html/uniondaint__data.html | 131 + .../dwc_otg/doc/html/uniondcfg__data.html | 74 + .../dwc_otg/doc/html/uniondctl__data.html | 96 + .../dwc_otg/doc/html/uniondepctl__data.html | 139 + .../dwc_otg/doc/html/uniondeptsiz0__data.html | 69 + .../dwc_otg/doc/html/uniondeptsiz__data.html | 63 + .../doc/html/uniondev__dma__desc__sts.html | 140 + .../doc/html/uniondevice__grxsts__data.html | 62 + .../dwc_otg/doc/html/uniondiepint__data.html | 90 + .../dwc_otg/doc/html/uniondoepint__data.html | 98 + .../dwc_otg/doc/html/uniondsts__data.html | 68 + .../dwc_otg/doc/html/uniondthrctl__data.html | 178 + .../dwc_otg/doc/html/uniondtknq1__data.html | 86 + .../dwc_otg/doc/html/uniondtxfsts__data.html | 56 + ...hcd_1_1dwc__otg__hcd__internal__flags.html | 66 + .../dwc_otg/doc/html/unionfifosize__data.html | 56 + .../dwc_otg/doc/html/uniongahbcfg__data.html | 66 + .../dwc_otg/doc/html/uniongi2cctl__data.html | 72 + .../dwc_otg/doc/html/uniongintmsk__data.html | 114 + .../dwc_otg/doc/html/uniongintsts__data.html | 114 + .../dwc_otg/doc/html/unionglpmctl__data.html | 178 + .../dwc_otg/doc/html/uniongnptxsts__data.html | 69 + .../dwc_otg/doc/html/uniongotgctl__data.html | 80 + .../dwc_otg/doc/html/uniongotgint__data.html | 79 + .../dwc_otg/doc/html/uniongrstctl__data.html | 249 + .../dwc_otg/doc/html/uniongusbcfg__data.html | 98 + .../dwc_otg/doc/html/unionhaint__data.html | 93 + .../dwc_otg/doc/html/unionhaintmsk__data.html | 93 + .../dwc_otg/doc/html/unionhcchar__data.html | 123 + .../dwc_otg/doc/html/unionhcdma__data.html | 78 + .../dwc_otg/doc/html/unionhcfg__data.html | 72 + .../dwc_otg/doc/html/unionhcint__data.html | 95 + .../dwc_otg/doc/html/unionhcintmsk__data.html | 82 + .../dwc_otg/doc/html/unionhcsplt__data.html | 63 + .../dwc_otg/doc/html/unionhctsiz__data.html | 105 + .../dwc_otg/doc/html/unionhfir__data.html | 54 + .../dwc_otg/doc/html/unionhfnum__data.html | 54 + .../doc/html/unionhost__dma__desc__sts.html | 123 + .../doc/html/unionhost__grxsts__data.html | 60 + .../dwc_otg/doc/html/unionhprt0__data.html | 82 + .../dwc_otg/doc/html/unionhptxsts__data.html | 62 + .../dwc_otg/doc/html/unionhwcfg1__data.html | 84 + .../dwc_otg/doc/html/unionhwcfg2__data.html | 82 + .../dwc_otg/doc/html/unionhwcfg3__data.html | 76 + .../dwc_otg/doc/html/unionhwcfg4__data.html | 80 + .../dwc_otg/doc/html/unionpcgcctl__data.html | 78 + drivers/usb/host/dwc_otg/dummy_audio.c | 1575 +++++ drivers/usb/host/dwc_otg/dwc_cfi_common.h | 142 + drivers/usb/host/dwc_otg/dwc_otg_attr.c | 1316 ++++ drivers/usb/host/dwc_otg/dwc_otg_attr.h | 88 + drivers/usb/host/dwc_otg/dwc_otg_cfi.c | 1876 ++++++ drivers/usb/host/dwc_otg/dwc_otg_cfi.h | 319 + drivers/usb/host/dwc_otg/dwc_otg_cil.c | 5410 +++++++++++++++++ drivers/usb/host/dwc_otg/dwc_otg_cil.h | 1143 ++++ drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c | 846 +++ drivers/usb/host/dwc_otg/dwc_otg_core_if.h | 641 ++ drivers/usb/host/dwc_otg/dwc_otg_dbg.h | 113 + drivers/usb/host/dwc_otg/dwc_otg_driver.c | 1577 +++++ drivers/usb/host/dwc_otg/dwc_otg_driver.h | 101 + drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 3330 ++++++++++ drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 804 +++ drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c | 1106 ++++ drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h | 393 ++ drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 2065 +++++++ drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 840 +++ drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 732 +++ drivers/usb/host/dwc_otg/dwc_otg_pcd.c | 2067 +++++++ drivers/usb/host/dwc_otg/dwc_otg_pcd.h | 216 + drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h | 333 + drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c | 4077 +++++++++++++ drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c | 1288 ++++ drivers/usb/host/dwc_otg/dwc_otg_regs.h | 2237 +++++++ drivers/usb/host/dwc_otg/test/Makefile | 16 + drivers/usb/host/dwc_otg/test/dwc_otg_test.pm | 337 + .../usb/host/dwc_otg/test/test_mod_param.pl | 133 + drivers/usb/host/dwc_otg/test/test_sysfs.pl | 193 + 341 files changed, 124762 insertions(+), 59 deletions(-) create mode 100644 drivers/usb/host/dwc_common_port/Makefile create mode 100644 drivers/usb/host/dwc_common_port/Makefile.linux create mode 100644 drivers/usb/host/dwc_common_port/doc/doxygen.cfg create mode 100644 drivers/usb/host/dwc_common_port/doc/html/dir_c13d72e45af28cdc461a5f284d3d36fc.html create mode 100644 drivers/usb/host/dwc_common_port/doc/html/dirs.html create mode 100644 drivers/usb/host/dwc_common_port/doc/html/doxygen.css create mode 100644 drivers/usb/host/dwc_common_port/doc/html/dwc__cc_8h.html create mode 100644 drivers/usb/host/dwc_common_port/doc/html/dwc__crypto_8c.html create mode 100644 drivers/usb/host/dwc_common_port/doc/html/dwc__crypto_8h.html create mode 100644 drivers/usb/host/dwc_common_port/doc/html/dwc__dh_8h.html create mode 100644 drivers/usb/host/dwc_common_port/doc/html/dwc__list_8h.html create mode 100644 drivers/usb/host/dwc_common_port/doc/html/dwc__modpow_8h.html create mode 100644 drivers/usb/host/dwc_common_port/doc/html/dwc__notifier_8h.html create mode 100644 drivers/usb/host/dwc_common_port/doc/html/dwc__os_8h.html create mode 100644 drivers/usb/host/dwc_common_port/doc/html/files.html create mode 100644 drivers/usb/host/dwc_common_port/doc/html/globals.html create mode 100644 drivers/usb/host/dwc_common_port/doc/html/globals_defs.html create mode 100644 drivers/usb/host/dwc_common_port/doc/html/globals_func.html create mode 100644 drivers/usb/host/dwc_common_port/doc/html/globals_type.html create mode 100644 drivers/usb/host/dwc_common_port/doc/html/index.html create mode 100644 drivers/usb/host/dwc_common_port/doc/html/main.html create mode 100644 drivers/usb/host/dwc_common_port/doc/html/pages.html create mode 100644 drivers/usb/host/dwc_common_port/doc/html/tabs.css create mode 100644 drivers/usb/host/dwc_common_port/doc/html/todo.html create mode 100644 drivers/usb/host/dwc_common_port/doc/html/tree.html create mode 100644 drivers/usb/host/dwc_common_port/dwc_cc.c create mode 100644 drivers/usb/host/dwc_common_port/dwc_cc.h create mode 100644 drivers/usb/host/dwc_common_port/dwc_common_linux.c create mode 100644 drivers/usb/host/dwc_common_port/dwc_crypto.c create mode 100644 drivers/usb/host/dwc_common_port/dwc_crypto.h create mode 100644 drivers/usb/host/dwc_common_port/dwc_dh.c create mode 100644 drivers/usb/host/dwc_common_port/dwc_dh.h create mode 100644 drivers/usb/host/dwc_common_port/dwc_list.h create mode 100644 drivers/usb/host/dwc_common_port/dwc_mem.c create mode 100644 drivers/usb/host/dwc_common_port/dwc_modpow.c create mode 100644 drivers/usb/host/dwc_common_port/dwc_modpow.h create mode 100644 drivers/usb/host/dwc_common_port/dwc_notifier.c create mode 100644 drivers/usb/host/dwc_common_port/dwc_notifier.h create mode 100644 drivers/usb/host/dwc_common_port/dwc_os.h create mode 100644 drivers/usb/host/dwc_common_port/usb.h create mode 100644 drivers/usb/host/dwc_otg/Makefile create mode 100644 drivers/usb/host/dwc_otg/doc/doxygen.cfg create mode 100644 drivers/usb/host/dwc_otg/doc/html/annotated.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/doxygen.css create mode 100644 drivers/usb/host/dwc_otg/doc/html/dummy__audio_8c-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__cfi__common_8h-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__cfi__common_8h.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__attr_8c-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__attr_8c.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__attr_8h-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__attr_8h.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__cfi_8c-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__cfi_8c.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__cfi_8h-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__cfi_8h.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil_8c-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil_8c.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil_8h-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil_8h.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil__intr_8c-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil__intr_8c.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__core__if_8h-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__core__if_8h.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__dbg_8h-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__dbg_8h.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__driver_8c-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__driver_8c.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__driver_8h-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__driver_8h.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd_8c-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd_8c.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd_8h-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd_8h.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__ddma_8c-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__ddma_8c.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__if_8h-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__if_8h.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__intr_8c-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__intr_8c.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__linux_8c-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__linux_8c.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__queue_8c-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__queue_8c.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd_8c-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd_8c.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd_8h-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd_8h.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__if_8h-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__if_8h.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__intr_8c-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__intr_8c.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__linux_8c-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__linux_8c.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__regs_8h-source.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/dwc__otg__regs_8h.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/files.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x62.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x63.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x64.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x65.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x66.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x67.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x68.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x69.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x6c.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x6d.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x6e.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x6f.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x70.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x71.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x72.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x73.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x74.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x75.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x76.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x77.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_0x78.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_func.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x62.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x63.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x64.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x65.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x66.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x67.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x68.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x69.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x6c.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x6d.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x6e.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x6f.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x70.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x71.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x72.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x73.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x74.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x75.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x76.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x77.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/functions_vars_0x78.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x61.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x62.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x63.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x64.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x65.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x66.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x67.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x68.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x69.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x6b.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x6d.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x6e.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x6f.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x70.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x71.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x72.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x73.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x74.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x75.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x76.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_0x77.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x61.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x62.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x63.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x64.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x66.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x67.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x68.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x69.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x6d.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x6e.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x6f.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x72.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x73.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x75.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_defs_0x76.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_enum.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_eval.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x61.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x62.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x63.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x64.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x65.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x66.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x67.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x68.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x69.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x6b.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x6d.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x70.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x71.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x72.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x73.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x75.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x76.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_func_0x77.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_type.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/globals_vars.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/index.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/linux module attributes.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/main.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/module parameters.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/pages.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/struct__ddma__align__buffer__setup.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/struct__ddma__concat__buffer__setup.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/struct__ddma__concat__buffer__setup__hdr.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/struct__ddma__sg__buffer__setup.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/struct__rx__fifo__size__setup.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/struct__tx__fifo__size__setup.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structcfi__all__features__header.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structcfi__dma__buff.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structcfi__ep.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structcfi__feature__desc__header.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structcfi__ops.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structcfi__string.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structcfi__usb__ctrlrequest.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structcfiobject.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__ep.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__hc.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__cil__callbacks.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__core__global__regs.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__core__if.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__core__params.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__dma__desc.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__global__regs.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__if.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__in__ep__regs.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__out__ep__regs.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__device.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__driver__module__params.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hc__regs.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd__function__ops.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd__iso__packet__desc.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd__pipe__info.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd__urb.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__host__dma__desc.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__host__global__regs.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__host__if.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__pcd.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__pcd__ep.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__pcd__function__ops.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__pcd__request.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__qh.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structdwc__otg__qtd.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structgadget__wrapper.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structiso__pkt__info.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structwrapper__priv__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/structzero__dev.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/tabs.css create mode 100644 drivers/usb/host/dwc_otg/doc/html/todo.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/tree.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondaint__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondcfg__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondctl__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondepctl__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondeptsiz0__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondeptsiz__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondev__dma__desc__sts.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondevice__grxsts__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondiepint__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondoepint__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondsts__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondthrctl__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondtknq1__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondtxfsts__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniondwc__otg__hcd_1_1dwc__otg__hcd__internal__flags.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionfifosize__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniongahbcfg__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniongi2cctl__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniongintmsk__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniongintsts__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionglpmctl__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniongnptxsts__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniongotgctl__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniongotgint__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniongrstctl__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/uniongusbcfg__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhaint__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhaintmsk__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhcchar__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhcdma__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhcfg__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhcint__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhcintmsk__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhcsplt__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhctsiz__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhfir__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhfnum__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhost__dma__desc__sts.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhost__grxsts__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhprt0__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhptxsts__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhwcfg1__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhwcfg2__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhwcfg3__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionhwcfg4__data.html create mode 100644 drivers/usb/host/dwc_otg/doc/html/unionpcgcctl__data.html create mode 100644 drivers/usb/host/dwc_otg/dummy_audio.c create mode 100644 drivers/usb/host/dwc_otg/dwc_cfi_common.h create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_attr.c create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_attr.h create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cfi.c create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cfi.h create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil.c create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil.h create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_core_if.h create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_dbg.h create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_driver.c create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_driver.h create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd.c create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd.h create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd.c create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd.h create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_regs.h create mode 100644 drivers/usb/host/dwc_otg/test/Makefile create mode 100644 drivers/usb/host/dwc_otg/test/dwc_otg_test.pm create mode 100644 drivers/usb/host/dwc_otg/test/test_mod_param.pl create mode 100644 drivers/usb/host/dwc_otg/test/test_sysfs.pl diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 30ddf8dc4f72..e56ebae7b09a 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_USB_U132_HCD) += host/ obj-$(CONFIG_USB_R8A66597_HCD) += host/ obj-$(CONFIG_USB_HWA_HCD) += host/ obj-$(CONFIG_USB_ISP1760_HCD) += host/ +obj-$(CONFIG_USB_DWCOTG) += host/ obj-$(CONFIG_USB_IMX21_HCD) += host/ obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/ diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 69ecd3c92311..0431b4efef17 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -149,6 +149,7 @@ int usb_choose_configuration(struct usb_device *udev) dev_warn(&udev->dev, "no configuration chosen from %d choice%s\n", num_configs, plural(num_configs)); + dev_warn(&udev->dev, "No support over %dmA\n", udev->bus_mA); } return i; } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 210e3597091a..badae51d2ff9 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1071,6 +1071,8 @@ static int hub_configure(struct usb_hub *hub, INIT_WORK(&hub->tt.clear_work, hub_tt_work); switch (hdev->descriptor.bDeviceProtocol) { case 0: + dev_dbg(hub_dev, "TT with no hub-specific protocol - " + "no TT\n"); break; case 1: dev_dbg(hub_dev, "Single TT\n"); @@ -1087,6 +1089,7 @@ static int hub_configure(struct usb_hub *hub, hub->tt.hub = hdev; break; case 3: + dev_dbg(hub_dev, "USB 3.0 hub - no TT\n"); /* USB 3.0 hubs don't have a TT */ break; default: @@ -1724,6 +1727,12 @@ static inline void announce_device(struct usb_device *udev) { } #endif #ifdef CONFIG_USB_OTG + +static int enable_whitelist; +module_param(enable_whitelist, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(enable_whitelist, + "only recognize devices in OTG whitelist if true"); + #include "otg_whitelist.h" #endif @@ -1778,9 +1787,15 @@ static int usb_enumerate_device_otg(struct usb_device *udev) dev_info(&udev->dev, "can't set HNP mode: %d\n", err); + dev_printk(KERN_CRIT, &udev->dev, + "Not Connected/Responding\n"); + bus->b_hnp_enable = 0; + } else { + dev_info(&udev->dev, + "HNP Not Supported\n"); } - } + } } } @@ -1789,12 +1804,27 @@ static int usb_enumerate_device_otg(struct usb_device *udev) /* Maybe it can talk to us, though we can't talk to it. * (Includes HNP test device.) */ - if (udev->bus->b_hnp_enable || udev->bus->is_b_host) { + if (udev->bus->b_hnp_enable || udev->bus->is_b_host || + udev->descriptor.idVendor == 0x1a0a) { err = usb_port_suspend(udev, PMSG_SUSPEND); - if (err < 0) + if (err < 0) { dev_dbg(&udev->dev, "HNP fail, %d\n", err); + } else { + /* Return Connection Refused(ECONNREFUSED) + * instead of No Device(ENODEV) so that the + * retry loop in hub_port_connect_change() is + * exited without disabling the port + */ + err = -ECONNREFUSED; + goto fail; + } } - err = -ENOTSUPP; + //err = -ENOTSUPP; + /* Return Not Connected (ENOTCONN) instead of No + * Device(ENODEV) so that the retry loop in + * hub_port_connect_change() is exited + */ + err = -ENOTCONN; goto fail; } fail: @@ -2377,8 +2407,8 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) status = 0; } else { /* device has up to 10 msec to fully suspend */ - dev_dbg(&udev->dev, "usb %ssuspend\n", - (msg.event & PM_EVENT_AUTO ? "auto-" : "")); +// dev_dbg(&udev->dev, "usb %ssuspend\n", +// (msg.event & PM_EVENT_AUTO ? "auto-" : "")); usb_set_device_state(udev, USB_STATE_SUSPENDED); msleep(10); } @@ -2932,7 +2962,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, buf->bMaxPacketSize0 = 0; r = usb_control_msg(udev, usb_rcvaddr0pipe(), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, - USB_DT_DEVICE << 8, 0, + USB_DT_DEVICE << 8, + //USB_DT_DEVICE << 64, // DWC patch suggestion! + 0, buf, GET_DESCRIPTOR_BUFSIZE, initial_descriptor_timeout); switch (buf->bMaxPacketSize0) { @@ -3353,8 +3385,10 @@ loop: release_devnum(udev); hub_free_dev(udev); usb_put_dev(udev); - if ((status == -ENOTCONN) || (status == -ENOTSUPP)) - break; + if (status == -ENOTCONN || status == -ENOTSUPP || + status == -ECONNREFUSED) + // break; //DWC patch + return; } if (hub->hdev->parent || !hcd->driver->port_handed_over || diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 0b5ec234c787..1abe797e4a27 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1836,6 +1836,85 @@ free_interfaces: if (cp->string == NULL && !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS)) cp->string = usb_cache_string(dev, cp->desc.iConfiguration); +/* Uncomment this define to enable the HS Electrical Test support */ +#define DWC_HS_ELECT_TST 1 +#ifdef DWC_HS_ELECT_TST + /* Here we implement the HS Electrical Test support. The + * tester uses a vendor ID of 0x1A0A to indicate we should + * run a special test sequence. The product ID tells us + * which sequence to run. We invoke the test sequence by + * sending a non-standard SetFeature command to our root + * hub port. Our dwc_otg_hcd_hub_control() routine will + * recognize the command and perform the desired test + * sequence. + */ + if (dev->descriptor.idVendor == 0x1A0A) { + /* HSOTG Electrical Test */ + dev_warn(&dev->dev, "VID from HSOTG Electrical Test Fixture\n"); + + if (dev->bus && dev->bus->root_hub) { + struct usb_device *hdev = dev->bus->root_hub; + dev_warn(&dev->dev, "Got PID 0x%x\n", dev->descriptor.idProduct); + + switch (dev->descriptor.idProduct) { + case 0x0101: /* TEST_SE0_NAK */ + dev_warn(&dev->dev, "TEST_SE0_NAK\n"); + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, + USB_PORT_FEAT_TEST, 0x300, NULL, 0, HZ); + break; + + case 0x0102: /* TEST_J */ + dev_warn(&dev->dev, "TEST_J\n"); + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, + USB_PORT_FEAT_TEST, 0x100, NULL, 0, HZ); + break; + + case 0x0103: /* TEST_K */ + dev_warn(&dev->dev, "TEST_K\n"); + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, + USB_PORT_FEAT_TEST, 0x200, NULL, 0, HZ); + break; + + case 0x0104: /* TEST_PACKET */ + dev_warn(&dev->dev, "TEST_PACKET\n"); + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, + USB_PORT_FEAT_TEST, 0x400, NULL, 0, HZ); + break; + + case 0x0105: /* TEST_FORCE_ENABLE */ + dev_warn(&dev->dev, "TEST_FORCE_ENABLE\n"); + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, + USB_PORT_FEAT_TEST, 0x500, NULL, 0, HZ); + break; + + case 0x0106: /* HS_HOST_PORT_SUSPEND_RESUME */ + dev_warn(&dev->dev, "HS_HOST_PORT_SUSPEND_RESUME\n"); + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, + USB_PORT_FEAT_TEST, 0x600, NULL, 0, 40 * HZ); + break; + + case 0x0107: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */ + dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup\n"); + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, + USB_PORT_FEAT_TEST, 0x700, NULL, 0, 40 * HZ); + break; + + case 0x0108: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */ + dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute\n"); + usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, + USB_PORT_FEAT_TEST, 0x800, NULL, 0, 40 * HZ); + } + } + } +#endif /* DWC_HS_ELECT_TST */ /* Now that all the interfaces are set up, register them * to trigger binding of drivers to interfaces. probe() diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h index e8cdce571bb1..3a0da17a459c 100644 --- a/drivers/usb/core/otg_whitelist.h +++ b/drivers/usb/core/otg_whitelist.h @@ -19,33 +19,82 @@ static struct usb_device_id whitelist_table [] = { /* hubs are optional in OTG, but very handy ... */ +#define CERT_WITHOUT_HUBS +#if defined(CERT_WITHOUT_HUBS) +{ USB_DEVICE( 0x0000, 0x0000 ), }, /* Root HUB Only*/ +#else { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), }, { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), }, +{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 2), }, +#endif #ifdef CONFIG_USB_PRINTER /* ignoring nonstatic linkage! */ /* FIXME actually, printers are NOT supposed to use device classes; * they're supposed to use interface classes... */ -{ USB_DEVICE_INFO(7, 1, 1) }, -{ USB_DEVICE_INFO(7, 1, 2) }, -{ USB_DEVICE_INFO(7, 1, 3) }, +//{ USB_DEVICE_INFO(7, 1, 1) }, +//{ USB_DEVICE_INFO(7, 1, 2) }, +//{ USB_DEVICE_INFO(7, 1, 3) }, #endif #ifdef CONFIG_USB_NET_CDCETHER /* Linux-USB CDC Ethernet gadget */ -{ USB_DEVICE(0x0525, 0xa4a1), }, +//{ USB_DEVICE(0x0525, 0xa4a1), }, /* Linux-USB CDC Ethernet + RNDIS gadget */ -{ USB_DEVICE(0x0525, 0xa4a2), }, +//{ USB_DEVICE(0x0525, 0xa4a2), }, #endif #if defined(CONFIG_USB_TEST) || defined(CONFIG_USB_TEST_MODULE) /* gadget zero, for testing */ -{ USB_DEVICE(0x0525, 0xa4a0), }, +//{ USB_DEVICE(0x0525, 0xa4a0), }, #endif + +/* OPT Tester */ +{ USB_DEVICE( 0x1a0a, 0x0101 ), }, /* TEST_SE0_NAK */ +{ USB_DEVICE( 0x1a0a, 0x0102 ), }, /* Test_J */ +{ USB_DEVICE( 0x1a0a, 0x0103 ), }, /* Test_K */ +{ USB_DEVICE( 0x1a0a, 0x0104 ), }, /* Test_PACKET */ +{ USB_DEVICE( 0x1a0a, 0x0105 ), }, /* Test_FORCE_ENABLE */ +{ USB_DEVICE( 0x1a0a, 0x0106 ), }, /* HS_PORT_SUSPEND_RESUME */ +{ USB_DEVICE( 0x1a0a, 0x0107 ), }, /* SINGLE_STEP_GET_DESCRIPTOR setup */ +{ USB_DEVICE( 0x1a0a, 0x0108 ), }, /* SINGLE_STEP_GET_DESCRIPTOR execute */ + +/* Sony cameras */ +{ USB_DEVICE_VER(0x054c,0x0010,0x0410, 0x0500), }, + +/* Memory Devices */ +//{ USB_DEVICE( 0x0781, 0x5150 ), }, /* SanDisk */ +//{ USB_DEVICE( 0x05DC, 0x0080 ), }, /* Lexar */ +//{ USB_DEVICE( 0x4146, 0x9281 ), }, /* IOMEGA */ +//{ USB_DEVICE( 0x067b, 0x2507 ), }, /* Hammer 20GB External HD */ +{ USB_DEVICE( 0x0EA0, 0x2168 ), }, /* Ours Technology Inc. (BUFFALO ClipDrive)*/ +//{ USB_DEVICE( 0x0457, 0x0150 ), }, /* Silicon Integrated Systems Corp. */ + +/* HP Printers */ +//{ USB_DEVICE( 0x03F0, 0x1102 ), }, /* HP Photosmart 245 */ +//{ USB_DEVICE( 0x03F0, 0x1302 ), }, /* HP Photosmart 370 Series */ + +/* Speakers */ +//{ USB_DEVICE( 0x0499, 0x3002 ), }, /* YAMAHA YST-MS35D USB Speakers */ +//{ USB_DEVICE( 0x0672, 0x1041 ), }, /* Labtec USB Headset */ { } /* Terminating entry */ }; +static inline void report_errors(struct usb_device *dev) +{ + /* OTG MESSAGE: report errors here, customize to match your product */ + dev_info(&dev->dev, "device Vendor:%04x Product:%04x is not supported\n", + le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); + if (USB_CLASS_HUB == dev->descriptor.bDeviceClass){ + dev_printk(KERN_CRIT, &dev->dev, "Unsupported Hub Topology\n"); + } else { + dev_printk(KERN_CRIT, &dev->dev, "Attached Device is not Supported\n"); + } +} + + static int is_targeted(struct usb_device *dev) { struct usb_device_id *id = whitelist_table; @@ -55,58 +104,83 @@ static int is_targeted(struct usb_device *dev) return 1; /* HNP test device is _never_ targeted (see OTG spec 6.6.6) */ - if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a && - le16_to_cpu(dev->descriptor.idProduct) == 0xbadd)) - return 0; - - /* NOTE: can't use usb_match_id() since interface caches - * aren't set up yet. this is cut/paste from that code. - */ - for (id = whitelist_table; id->match_flags; id++) { - if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && - id->idVendor != le16_to_cpu(dev->descriptor.idVendor)) - continue; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) && - id->idProduct != le16_to_cpu(dev->descriptor.idProduct)) - continue; - - /* No need to test id->bcdDevice_lo != 0, since 0 is never - greater than any unsigned number. */ - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) && - (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice))) - continue; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) && - (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice))) - continue; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) && - (id->bDeviceClass != dev->descriptor.bDeviceClass)) - continue; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) && - (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass)) - continue; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) && - (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol)) - continue; + if (dev->descriptor.idVendor == 0x1a0a && + dev->descriptor.idProduct == 0xbadd) { + return 0; + } else if (!enable_whitelist) { + return 1; + } else { + +#ifdef DEBUG + dev_dbg(&dev->dev, "device V:%04x P:%04x DC:%04x SC:%04x PR:%04x \n", + dev->descriptor.idVendor, + dev->descriptor.idProduct, + dev->descriptor.bDeviceClass, + dev->descriptor.bDeviceSubClass, + dev->descriptor.bDeviceProtocol); +#endif return 1; + /* NOTE: can't use usb_match_id() since interface caches + * aren't set up yet. this is cut/paste from that code. + */ + for (id = whitelist_table; id->match_flags; id++) { +#ifdef DEBUG + dev_dbg(&dev->dev, + "ID: V:%04x P:%04x DC:%04x SC:%04x PR:%04x \n", + id->idVendor, + id->idProduct, + id->bDeviceClass, + id->bDeviceSubClass, + id->bDeviceProtocol); +#endif + + if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && + id->idVendor != le16_to_cpu(dev->descriptor.idVendor)) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) && + id->idProduct != le16_to_cpu(dev->descriptor.idProduct)) + continue; + + /* No need to test id->bcdDevice_lo != 0, since 0 is never + greater than any unsigned number. */ + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) && + (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice))) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) && + (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice))) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) && + (id->bDeviceClass != dev->descriptor.bDeviceClass)) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) && + (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass)) + continue; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) && + (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol)) + continue; + + return 1; + } } /* add other match criteria here ... */ - - /* OTG MESSAGE: report errors here, customize to match your product */ - dev_err(&dev->dev, "device v%04x p%04x is not supported\n", - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); #ifdef CONFIG_USB_OTG_WHITELIST + report_errors(dev); return 0; #else - return 1; + if (enable_whitelist) { + report_errors(dev); + return 0; + } else { + return 1; + } #endif } diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 6f5049156e17..83de3752aff8 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -525,6 +525,34 @@ config USB_GADGET_SUPERSPEED depends on USB_GADGET depends on USB_GADGET_DUALSPEED +config USB_GADGET_SNPS_DWC_OTG + boolean "Synopsys Driver for DWC_otg Controller" + depends on USB && EXPERIMENTAL + select USB_OTG + select USB_GADGET_DUALSPEED + help + Selects the Synopsys Driver for the DWC_otg Controller. + +config USB_DWC_OTG_LPM + boolean "Enable LPM support" + depends on USB && EXPERIMENTAL + help + Enables LPM support. + +config USB_GADGET_SNPS_DWC_OTG + boolean "Synopsys Driver for DWC_otg Controller" + depends on USB && EXPERIMENTAL + select USB_OTG + select USB_GADGET_DUALSPEED + help + Selects the Synopsys Driver for the DWC_otg Controller. + +config USB_DWC_OTG_LPM + boolean "Enable LPM support" + depends on USB && EXPERIMENTAL + help + Enables LPM support. + # # USB Gadget Drivers # diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 639e14a2fd15..1554bc098d23 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -572,8 +572,37 @@ config_desc = { .iConfiguration = FSG_STRING_CONFIG, .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2, + //.bMaxPower = 0, //unused suggestion by DWC patch }; +#ifdef CONFIG_USB_DWC_OTG_LPM +#define USB_DEVICE_CAPABILITY_20_EXTENSION 0x02 +#define USB_20_EXT_LPM 0x02 +typedef struct usb_dev_cap_20_ext_desc { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDevCapabilityType; + __le32 bmAttributes; +} __attribute__ ((__packed__)) usb_dev_cap_20_ext_desc_t; + +static struct usb_bos_20_ext_desc { + struct usb_bos_descriptor bos_desc; + struct usb_dev_cap_20_ext_desc dev_cap_20_ext_desc; +} __attribute__ ((__packed__)) bos_20_ext_desc = { + { + .bLength = sizeof(struct usb_bos_descriptor), + .bDescriptorType = USB_DT_BOS, + .wTotalLength = sizeof(struct usb_bos_20_ext_desc), + .bNumDeviceCaps = 1, + }, + { + .bLength = sizeof(struct usb_dev_cap_20_ext_desc), + .bDescriptorType = USB_DT_DEVICE_CAPABILITY, + .bDevCapabilityType = USB_DEVICE_CAPABILITY_20_EXTENSION, + .bmAttributes = USB_20_EXT_LPM, + }, +}; +#endif static struct usb_qualifier_descriptor dev_qualifier = { @@ -967,6 +996,24 @@ get_config: value = usb_gadget_get_string(&fsg_stringtab, w_value & 0xff, req->buf); break; +#ifdef CONFIG_USB_DWC_OTG_LPM + case USB_DT_BOS: + /* When the PCD has LPM enabled set the LPM + * Feature bit to 1 when not enabled set the + * bit to 0. */ + if (usb_gadget_test_lpm_support(fsg->gadget)) { + VDBG(fsg, "LPM support enabled in DWC UDC PCD\n"); + bos_20_ext_desc.dev_cap_20_ext_desc.bmAttributes |= USB_20_EXT_LPM; + } else { + VDBG(fsg, "LPM support disabled in DWC UDC PCD\n"); + bos_20_ext_desc.dev_cap_20_ext_desc.bmAttributes &= ~USB_20_EXT_LPM; + } + DBG(fsg, "sending BOS descriptor to host\n"); + value = sizeof bos_20_ext_desc; + memcpy(req->buf, &bos_20_ext_desc, value); + break; +#endif + } break; @@ -2630,6 +2677,9 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) fsg_set_halt(fsg, fsg->bulk_out); halt_bulk_in_endpoint(fsg); } + fsg->bulk_in->ops->set_halt(fsg->bulk_in, 3); + fsg_set_halt(fsg, fsg->bulk_out); + fsg->bulk_out->ops->set_halt(fsg->bulk_out, 3); return -EINVAL; } @@ -2986,7 +3036,8 @@ static void handle_exception(struct fsg_dev *fsg) * bulk endpoint, clear the halt now. (The SuperH UDC * requires this.) */ if (test_and_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags)) - usb_ep_clear_halt(fsg->bulk_in); + //usb_ep_clear_halt(fsg->bulk_in); //DWC patch: + fsg->bulk_in->ops->set_halt(fsg->bulk_in, 2); if (transport_is_bbb()) { if (fsg->ep0_req_tag == exception_req_tag) @@ -3060,6 +3111,9 @@ static int fsg_main_thread(void *fsg_) * that expects a __user pointer and it will work okay. */ set_fs(get_ds()); + /* Setting this thread high priority */ + set_user_nice(current, -20); + /* The main loop */ while (fsg->state != FSG_STATE_TERMINATED) { if (exception_in_progress(fsg) || signal_pending(current)) { @@ -3207,6 +3261,13 @@ static int __init check_parameters(struct fsg_dev *fsg) gcnum = usb_gadget_controller_number(fsg->gadget); if (gcnum >= 0) mod_data.release = 0x0300 + gcnum; + else if (gadget_is_dwc_otg(fsg->gadget)) { + mod_data.release = __constant_cpu_to_le16 (0x0200); + mod_data.vendor = __constant_cpu_to_le16 (0x053f); + if (mod_data.product == DRIVER_PRODUCT_ID) { + mod_data.product = __constant_cpu_to_le16 (0x0000); + } + } else { WARNING(fsg, "controller '%s' not recognized\n", fsg->gadget->name); @@ -3450,6 +3511,13 @@ static int __init fsg_bind(struct usb_gadget *gadget) rc = -ENOMEM; +#ifdef CONFIG_USB_DWC_OTG_LPM + /* When LPM is enabled, Inform the host that the remote wake + * up capability is supported. */ + if (usb_gadget_test_lpm_support(fsg->gadget)) + config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; +#endif + /* Allocate the request and buffer for endpoint 0 */ fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL); if (!req) diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index ab085f12d570..3b8ea349394c 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -543,6 +543,19 @@ config USB_HWA_HCD To compile this driver a module, choose M here: the module will be called "hwa-hc". +config USB_DWCOTG + tristate "Synopsis DWC host support" + depends on USB + help + The Synopsis DWC controller is a dual-role + host/peripheral/OTG ("On The Go") USB controllers. + + Enable this option to support this IP in host controller mode. + If unsure, say N. + + To compile this driver as a module, choose M here: the + modules built will be called dwc_otg and dwc_common_port. + config USB_IMX21_HCD tristate "iMX21 HCD support" depends on USB && ARM && MACH_MX21 diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 624a362f2fee..c4264cee6814 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -32,6 +32,8 @@ obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o + +obj-$(CONFIG_USB_DWCOTG) += dwc_otg/ dwc_common_port/ obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o diff --git a/drivers/usb/host/dwc_common_port/Makefile b/drivers/usb/host/dwc_common_port/Makefile new file mode 100644 index 000000000000..3b2ac7061261 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/Makefile @@ -0,0 +1,44 @@ +# +# Makefile for DWC_common library +# + +ifneq ($(KERNELRELEASE),) + +#CPPFLAGS += -DDEBUG_MEMORY + +CPPFLAGS += -DDEBUG +CPPFLAGS += -DDWC_LINUX + +obj-$(CONFIG_USB_DWCOTG) += dwc_common_port_lib.o +dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \ + dwc_crypto.o dwc_notifier.o \ + dwc_common_linux.o dwc_mem.o + +kernrelwd := $(subst ., ,$(KERNELRELEASE)) +kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd)) + +ifneq ($(kernrel3),2.6.20) +# grayg - I only know that we use EXTRA_CFLAGS in 2.6.31 actually +EXTRA_CFLAGS += $(CPPFLAGS) +endif + +else + +ifeq ($(DOXYGEN),) +DOXYGEN := $(DOXYGEN) +endif + +default: + $(MAKE) -C$(KDIR) M=$(PWD) modules + +docs: $(wildcard *.[hc]) doc/doxygen.cfg + $(DOXYGEN) doc/doxygen.cfg + +tags: $(wildcard *.[hc]) + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h) + +endif + +clean: + rm -rf *.o *.ko .*cmd *.mod.c .tmp_versions Module.symvers + diff --git a/drivers/usb/host/dwc_common_port/Makefile.linux b/drivers/usb/host/dwc_common_port/Makefile.linux new file mode 100644 index 000000000000..a553a9d52f86 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/Makefile.linux @@ -0,0 +1,36 @@ +# +# Makefile for DWC_common library +# +ifneq ($(KERNELRELEASE),) + +#CPPFLAGS += -DDEBUG_MEMORY + +#CPPFLAGS += -DDEBUG +CPPFLAGS += -DDWC_LINUX + +obj-m := dwc_common_port_lib.o +dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \ + dwc_crypto.o dwc_notifier.o \ + dwc_common_linux.o dwc_mem.o + +else + + +ifeq ($(DOXYGEN),) +DOXYGEN := $(DOXYGEN) +endif + +default: + $(MAKE) -C$(KDIR) M=$(PWD) modules + +docs: $(wildcard *.[hc]) doc/doxygen.cfg + $(DOXYGEN) doc/doxygen.cfg + +tags: $(wildcard *.[hc]) + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h) + +endif + +clean: + rm -rf *.o *.ko .*cmd *.mod.c .tmp_versions Module.symvers + diff --git a/drivers/usb/host/dwc_common_port/doc/doxygen.cfg b/drivers/usb/host/dwc_common_port/doc/doxygen.cfg new file mode 100644 index 000000000000..605b9dab94e5 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/doxygen.cfg @@ -0,0 +1,270 @@ +# Doxyfile 1.4.5 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = "Synopsys DWC Portability and Common Library for UWB" +PROJECT_NUMBER = +OUTPUT_DIRECTORY = doc +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = YES +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = .. +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = YES +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +BUILTIN_STL_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = NO +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = NO +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = NO +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = NO +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = . +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.C \ + *.CC \ + *.C++ \ + *.II \ + *.I++ \ + *.H \ + *.HH \ + *.H++ \ + *.CS \ + *.PHP \ + *.PHP3 \ + *.M \ + *.MM \ + *.PY +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +USE_HTAGS = NO +VERBATIM_HEADERS = NO +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = YES +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = DEBUG DEBUG_MEMORY +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = NO +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/drivers/usb/host/dwc_common_port/doc/html/dir_c13d72e45af28cdc461a5f284d3d36fc.html b/drivers/usb/host/dwc_common_port/doc/html/dir_c13d72e45af28cdc461a5f284d3d36fc.html new file mode 100644 index 000000000000..0b427241ef67 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/dir_c13d72e45af28cdc461a5f284d3d36fc.html @@ -0,0 +1,81 @@ + + +Synopsys DWC Portability and Common Library for UWB: dwc_common_port/ Directory Reference + + + + + + +

dwc_common_port Directory Reference

+

+ + + + + + + + + +

+

+ + + + + +

+

+ + + +

+

+ + + + + +

+

+ + + +

+

+ + + + + + + +

+

+ + + + + +

+

+ + + +

+

+ +

Files

file  dwc_cc.c
file  dwc_cc.h
 This file defines the Context Context library.
file  dwc_common_linux.c
file  dwc_crypto.c
 This file contains the WUSB cryptographic routines.
file  dwc_crypto.h
 This file contains declarations for the WUSB Cryptographic routines as defined in the WUSB spec.
file  dwc_dh.c
file  dwc_dh.h
 This file defines the common functions on device and host for performing numeric association as defined in the WUSB spec.
file  dwc_list.h
 This file defines linked list operations.
file  dwc_mem.c
file  dwc_modpow.c
file  dwc_modpow.h
 This file defines the module exponentiation function which is only used internally by the DWC UWB modules for calculation of PKs during numeric association.
file  dwc_notifier.c
file  dwc_notifier.h
 A simple implementation of the Observer pattern.
file  dwc_os.h
 DWC portability library, low level os-wrapper functions.
file  usb.h
+


Generated on Tue May 5 02:22:50 2009 for Synopsys DWC Portability and Common Library for UWB by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_common_port/doc/html/dirs.html b/drivers/usb/host/dwc_common_port/doc/html/dirs.html new file mode 100644 index 000000000000..baaf2da9b481 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/dirs.html @@ -0,0 +1,22 @@ + + +Synopsys DWC Portability and Common Library for UWB: Directory Hierarchy + + + + + +

Synopsys DWC Portability and Common Library for UWB Directories

This directory hierarchy is sorted roughly, but not completely, alphabetically: +
Generated on Tue May 5 02:22:50 2009 for Synopsys DWC Portability and Common Library for UWB by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_common_port/doc/html/doxygen.css b/drivers/usb/host/dwc_common_port/doc/html/doxygen.css new file mode 100644 index 000000000000..5d583694ed46 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/doxygen.css @@ -0,0 +1,358 @@ +BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { + font-family: Geneva, Arial, Helvetica, sans-serif; +} +BODY,TD { + font-size: 90%; +} +H1 { + text-align: center; + font-size: 160%; +} +H2 { + font-size: 120%; +} +H3 { + font-size: 100%; +} +CAPTION { font-weight: bold } +DIV.qindex { + width: 100%; + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 140%; +} +DIV.nav { + width: 100%; + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 140%; +} +DIV.navtab { + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} +TD.navtab { + font-size: 70%; +} +A.qindex { + text-decoration: none; + font-weight: bold; + color: #1A419D; +} +A.qindex:visited { + text-decoration: none; + font-weight: bold; + color: #1A419D +} +A.qindex:hover { + text-decoration: none; + background-color: #ddddff; +} +A.qindexHL { + text-decoration: none; + font-weight: bold; + background-color: #6666cc; + color: #ffffff; + border: 1px double #9295C2; +} +A.qindexHL:hover { + text-decoration: none; + background-color: #6666cc; + color: #ffffff; +} +A.qindexHL:visited { text-decoration: none; background-color: #6666cc; color: #ffffff } +A.el { text-decoration: none; font-weight: bold } +A.elRef { font-weight: bold } +A.code:link { text-decoration: none; font-weight: normal; color: #0000FF} +A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF} +A.codeRef:link { font-weight: normal; color: #0000FF} +A.codeRef:visited { font-weight: normal; color: #0000FF} +A:hover { text-decoration: none; background-color: #f2f2ff } +DL.el { margin-left: -1cm } +.fragment { + font-family: monospace, fixed; + font-size: 95%; +} +PRE.fragment { + border: 1px solid #CCCCCC; + background-color: #f5f5f5; + margin-top: 4px; + margin-bottom: 4px; + margin-left: 2px; + margin-right: 8px; + padding-left: 6px; + padding-right: 6px; + padding-top: 4px; + padding-bottom: 4px; +} +DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px } + +DIV.groupHeader { + margin-left: 16px; + margin-top: 12px; + margin-bottom: 6px; + font-weight: bold; +} +DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% } +BODY { + background: white; + color: black; + margin-right: 20px; + margin-left: 20px; +} +TD.indexkey { + background-color: #e8eef2; + font-weight: bold; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +TD.indexvalue { + background-color: #e8eef2; + font-style: italic; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +TR.memlist { + background-color: #f0f0f0; +} +P.formulaDsp { text-align: center; } +IMG.formulaDsp { } +IMG.formulaInl { vertical-align: middle; } +SPAN.keyword { color: #008000 } +SPAN.keywordtype { color: #604020 } +SPAN.keywordflow { color: #e08000 } +SPAN.comment { color: #800000 } +SPAN.preprocessor { color: #806020 } +SPAN.stringliteral { color: #002080 } +SPAN.charliteral { color: #008080 } +.mdescLeft { + padding: 0px 8px 4px 8px; + font-size: 80%; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.mdescRight { + padding: 0px 8px 4px 8px; + font-size: 80%; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.memItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplParams { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + color: #606060; + background-color: #FAFAFA; + font-size: 80%; +} +.search { color: #003399; + font-weight: bold; +} +FORM.search { + margin-bottom: 0px; + margin-top: 0px; +} +INPUT.search { font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +TD.tiny { font-size: 75%; +} +a { + color: #1A41A8; +} +a:visited { + color: #2A3798; +} +.dirtab { padding: 4px; + border-collapse: collapse; + border: 1px solid #84b0c7; +} +TH.dirtab { background: #e8eef2; + font-weight: bold; +} +HR { height: 1px; + border: none; + border-top: 1px solid black; +} + +/* Style for detailed member documentation */ +.memtemplate { + font-size: 80%; + color: #606060; + font-weight: normal; +} +.memnav { + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} +.memitem { + padding: 4px; + background-color: #eef3f5; + border-width: 1px; + border-style: solid; + border-color: #dedeee; + -moz-border-radius: 8px 8px 8px 8px; +} +.memname { + white-space: nowrap; + font-weight: bold; +} +.memdoc{ + padding-left: 10px; +} +.memproto { + background-color: #d5e1e8; + width: 100%; + border-width: 1px; + border-style: solid; + border-color: #84b0c7; + font-weight: bold; + -moz-border-radius: 8px 8px 8px 8px; +} +.paramkey { + text-align: right; +} +.paramtype { + white-space: nowrap; +} +.paramname { + color: #602020; + font-style: italic; +} +/* End Styling for detailed member documentation */ + +/* for the tree view */ +.ftvtree { + font-family: sans-serif; + margin:0.5em; +} +.directory { font-size: 9pt; font-weight: bold; } +.directory h3 { margin: 0px; margin-top: 1em; font-size: 11pt; } +.directory > h3 { margin-top: 0; } +.directory p { margin: 0px; white-space: nowrap; } +.directory div { display: none; margin: 0px; } +.directory img { vertical-align: -30%; } + diff --git a/drivers/usb/host/dwc_common_port/doc/html/dwc__cc_8h.html b/drivers/usb/host/dwc_common_port/doc/html/dwc__cc_8h.html new file mode 100644 index 000000000000..6bf6e7c35dcb --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/dwc__cc_8h.html @@ -0,0 +1,709 @@ + + +Synopsys DWC Portability and Common Library for UWB: dwc_cc.h File Reference + + + + + + + +

dwc_cc.h File Reference


Detailed Description

+This file defines the Context Context library. +

+The main data structure is dwc_cc_if_t which is returned by either the dwc_cc_if_alloc function or returned by the module to the user via a provided function. The data structure is opaque and should only be manipulated via the functions provied in this API.

+It manages a list of connection contexts and operations can be performed to add, remove, query, search, and change, those contexts. Additionally, a dwc_notifier_t object can be requested from the manager so that the user can be notified whenever the context list has changed. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Connection Context Operations

dwc_cc_if_t * dwc_cc_if_alloc (dwc_notifier_t *notifier, unsigned is_host)
 This function allocates memory for a dwc_cc_if_t structure, initializes fields to default values, and returns a pointer to the structure or NULL on error.
void dwc_cc_if_free (dwc_cc_if_t *cc_if)
 Frees the memory for the specified CC structure allocated from dwc_cc_if_alloc().
void dwc_cc_clear (dwc_cc_if_t *cc_if)
 Removes all contexts from the connection context list.
int32_t dwc_cc_add (dwc_cc_if_t *cc_if, uint8_t *chid, uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
 Adds a connection context (CHID, CK, CDID, Name) to the connection context list.
void dwc_cc_change (dwc_cc_if_t *cc_if, int32_t id, uint8_t *chid, uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length)
 Changes the CHID, CK, CDID, or Name values of a connection context in the list, preserving any accumulated statistics.
void dwc_cc_remove (dwc_cc_if_t *cc_if, int32_t id)
 Remove the specified connection context.
uint8_t * dwc_cc_data_for_save (dwc_cc_if_t *cc_if, unsigned int *length)
 Get a binary block of data for the connection context list and attributes.
void dwc_cc_restore_from_data (dwc_cc_if_t *cc_if, uint8_t *data, unsigned int length)
 Restore the connection context list from the binary data that was previously returned from a call to dwc_cc_data_for_save.
uint32_t dwc_cc_match_chid (dwc_cc_if_t *cc_if, uint8_t *chid)
 Find the connection context from the specified CHID.
uint32_t dwc_cc_match_cdid (dwc_cc_if_t *cc_if, uint8_t *cdid)
 Find the connection context from the specified CDID.
uint8_t * dwc_cc_ck (dwc_cc_if_t *cc_if, int32_t id)
 Retrieve the CK from the specified connection context.
uint8_t * dwc_cc_chid (dwc_cc_if_t *cc_if, int32_t id)
 Retrieve the CHID from the specified connection context.
uint8_t * dwc_cc_cdid (dwc_cc_if_t *cc_if, int32_t id)
 Retrieve the CDID from the specified connection context.
+uint8_t * dwc_cc_name (dwc_cc_if_t *cc_if, int32_t id, uint8_t *length)
static unsigned dwc_assoc_is_not_zero_id (uint8_t *id)
 Checks a buffer for non-zero.
static unsigned dwc_assoc_is_zero_id (uint8_t *id)
 Checks a buffer for zero.
static int dwc_print_id_string (char *buffer, uint8_t *id)
 Prints an ASCII representation for the 16-byte chid, cdid, or ck, into buffer.

Defines

+#define DWC_CC_LIST_CHANGED_NOTIFICATION   "DWC_CC_LIST_CHANGED_NOTIFICATION"

Typedefs

+typedef dwc_cc_if dwc_cc_if_t
+


Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
dwc_cc_if_t* dwc_cc_if_alloc (dwc_notifier_t *  notifier,
unsigned  is_host 
)
+
+
+ +

+This function allocates memory for a dwc_cc_if_t structure, initializes fields to default values, and returns a pointer to the structure or NULL on error. +

+ +

+

+ +

+
+ + + + + + + + + +
void dwc_cc_if_free (dwc_cc_if_t *  cc_if  ) 
+
+
+ +

+Frees the memory for the specified CC structure allocated from dwc_cc_if_alloc(). +

+ +

+

+ +

+
+ + + + + + + + + +
void dwc_cc_clear (dwc_cc_if_t *  cc_if  ) 
+
+
+ +

+Removes all contexts from the connection context list. +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int32_t dwc_cc_add (dwc_cc_if_t *  cc_if,
uint8_t *  chid,
uint8_t *  cdid,
uint8_t *  ck,
uint8_t *  name,
uint8_t  length 
)
+
+
+ +

+Adds a connection context (CHID, CK, CDID, Name) to the connection context list. +

+If a CHID already exists, the CK and name are overwritten. Statistics are not overwritten.

+

Parameters:
+ + + + + + + +
cc_if The cc_if structure.
chid A pointer to the 16-byte CHID. This value will be copied.
ck A pointer to the 16-byte CK. This value will be copied.
cdid A pointer to the 16-byte CDID. This value will be copied.
name An optional host friendly name as defined in the association model spec. Must be a UTF16-LE unicode string. Can be NULL to indicated no name.
length The length othe unicode string.
+
+
Returns:
A unique identifier used to refer to this context that is valid for as long as this context is still in the list.
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_cc_change (dwc_cc_if_t *  cc_if,
int32_t  id,
uint8_t *  chid,
uint8_t *  cdid,
uint8_t *  ck,
uint8_t *  name,
uint8_t  length 
)
+
+
+ +

+Changes the CHID, CK, CDID, or Name values of a connection context in the list, preserving any accumulated statistics. +

+This would typically be called if the host decideds to change the context with a SET_CONNECTION request.

+

Parameters:
+ + + + + + + + +
cc_if The cc_if structure.
id The identifier of the connection context.
chid A pointer to the 16-byte CHID. This value will be copied. NULL indicates no change.
cdid A pointer to the 16-byte CDID. This value will be copied. NULL indicates no change.
ck A pointer to the 16-byte CK. This value will be copied. NULL indicates no change.
name Host friendly name UTF16-LE. NULL indicates no change.
length Length of name.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_cc_remove (dwc_cc_if_t *  cc_if,
int32_t  id 
)
+
+
+ +

+Remove the specified connection context. +

+

Parameters:
+ + + +
cc_if The cc_if structure.
id The identifier of the connection context to remove.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
uint8_t* dwc_cc_data_for_save (dwc_cc_if_t *  cc_if,
unsigned int *  length 
)
+
+
+ +

+Get a binary block of data for the connection context list and attributes. +

+This data can be used by the OS specific driver to save the connection context list into non-volatile memory.

+

Parameters:
+ + + +
cc_if The cc_if structure.
length Return the length of the data buffer.
+
+
Returns:
A pointer to the data buffer. The memory for this buffer should be freed with DWC_FREE() after use.
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_cc_restore_from_data (dwc_cc_if_t *  cc_if,
uint8_t *  data,
unsigned int  length 
)
+
+
+ +

+Restore the connection context list from the binary data that was previously returned from a call to dwc_cc_data_for_save. +

+This can be used by the OS specific driver to load a connection context list from non-volatile memory.

+

Parameters:
+ + + + +
cc_if The cc_if structure.
data The data bytes as returned from dwc_cc_data_for_save.
length The length of the data.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
uint32_t dwc_cc_match_chid (dwc_cc_if_t *  cc_if,
uint8_t *  chid 
)
+
+
+ +

+Find the connection context from the specified CHID. +

+

Parameters:
+ + + +
cc_if The cc_if structure.
chid A pointer to the CHID data.
+
+
Returns:
A non-zero identifier of the connection context if the CHID matches. Otherwise returns 0.
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
uint32_t dwc_cc_match_cdid (dwc_cc_if_t *  cc_if,
uint8_t *  cdid 
)
+
+
+ +

+Find the connection context from the specified CDID. +

+

Parameters:
+ + + +
cc_if The cc_if structure.
cdid A pointer to the CDID data.
+
+
Returns:
A non-zero identifier of the connection context if the CHID matches. Otherwise returns 0.
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
uint8_t* dwc_cc_ck (dwc_cc_if_t *  cc_if,
int32_t  id 
)
+
+
+ +

+Retrieve the CK from the specified connection context. +

+

Parameters:
+ + + +
cc_if The cc_if structure.
id The identifier of the connection context.
+
+
Returns:
A pointer to the CK data. The memory does not need to be freed.
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
uint8_t* dwc_cc_chid (dwc_cc_if_t *  cc_if,
int32_t  id 
)
+
+
+ +

+Retrieve the CHID from the specified connection context. +

+

Parameters:
+ + + +
cc_if The cc_if structure.
id The identifier of the connection context.
+
+
Returns:
A pointer to the CHID data. The memory does not need to be freed.
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
uint8_t* dwc_cc_cdid (dwc_cc_if_t *  cc_if,
int32_t  id 
)
+
+
+ +

+Retrieve the CDID from the specified connection context. +

+

Parameters:
+ + + +
cc_if The cc_if structure.
id The identifier of the connection context.
+
+
Returns:
A pointer to the CDID data. The memory does not need to be freed.
+ +
+

+ +

+
+ + + + + + + + + +
static unsigned dwc_assoc_is_not_zero_id (uint8_t *  id  )  [inline, static]
+
+
+ +

+Checks a buffer for non-zero. +

+

Parameters:
+ + +
id A pointer to a 16 byte buffer.
+
+
Returns:
true if the 16 byte value is non-zero.
+ +
+

+ +

+
+ + + + + + + + + +
static unsigned dwc_assoc_is_zero_id (uint8_t *  id  )  [inline, static]
+
+
+ +

+Checks a buffer for zero. +

+

Parameters:
+ + +
id A pointer to a 16 byte buffer.
+
+
Returns:
true if the 16 byte value is zero.
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static int dwc_print_id_string (char *  buffer,
uint8_t *  id 
) [inline, static]
+
+
+ +

+Prints an ASCII representation for the 16-byte chid, cdid, or ck, into buffer. +

+ +

+

+


Generated on Tue May 5 02:22:50 2009 for Synopsys DWC Portability and Common Library for UWB by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_common_port/doc/html/dwc__crypto_8c.html b/drivers/usb/host/dwc_common_port/doc/html/dwc__crypto_8c.html new file mode 100644 index 000000000000..0e0e6e919b1b --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/dwc__crypto_8c.html @@ -0,0 +1,435 @@ + + +Synopsys DWC Portability and Common Library for UWB: dwc_crypto.c File Reference + + + + + + + +

dwc_crypto.c File Reference


Detailed Description

+This file contains the WUSB cryptographic routines. +

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Functions

+static void dump_bytes (char *name, uint8_t *bytes, int len)
+void show_block (const u8 *blk, const char *prefix, const char *suffix, int a)
int dwc_wusb_aes_encrypt (u8 *src, u8 *key, u8 *dst)
 Encrypts an array of bytes using the AES encryption engine.
void dwc_wusb_cmf (u8 *key, u8 *nonce, char *label, u8 *bytes, int len, u8 *result)
 The CCM-MAC-FUNCTION described in section 6.5 of the WUSB spec.
void dwc_wusb_prf (int prf_len, u8 *key, u8 *nonce, char *label, u8 *bytes, int len, u8 *result)
 The PRF function described in section 6.5 of the WUSB spec.
void dwc_wusb_fill_ccm_nonce (uint16_t haddr, uint16_t daddr, uint8_t *tkid, uint8_t *nonce)
 Fills in CCM Nonce per the WUSB spec.
void dwc_wusb_gen_nonce (uint16_t addr, uint8_t *nonce)
 Generates a 16-byte cryptographic-grade random number for the Host/Device Nonce.
void dwc_wusb_gen_key (uint8_t *ccm_nonce, uint8_t *mk, uint8_t *hnonce, uint8_t *dnonce, uint8_t *kck, uint8_t *ptk)
 Generates the Session Key (PTK) and Key Confirmation Key (KCK) per the WUSB spec.
void dwc_wusb_gen_mic (uint8_t *ccm_nonce, uint8_t *kck, uint8_t *data, uint8_t *mic)
 Generates the Message Integrity Code over the Handshake data per the WUSB spec.
+


Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_wusb_aes_encrypt (u8 *  src,
u8 *  key,
u8 *  dst 
)
+
+
+ +

+Encrypts an array of bytes using the AES encryption engine. +

+If dst == src, then the bytes will be encrypted in-place.

+

Returns:
0 on success, negative error code on error.
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_wusb_cmf (u8 *  key,
u8 *  nonce,
char *  label,
u8 *  bytes,
int  len,
u8 *  result 
)
+
+
+ +

+The CCM-MAC-FUNCTION described in section 6.5 of the WUSB spec. +

+This function takes a data string and returns the encrypted CBC Counter-mode MIC.

+

Parameters:
+ + + + + + + +
key The 128-bit symmetric key.
nonce The CCM nonce.
label The unique 14-byte ASCII text label.
bytes The byte array to be encrypted.
len Length of the byte array.
result Byte array to receive the 8-byte encrypted MIC.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_wusb_prf (int  prf_len,
u8 *  key,
u8 *  nonce,
char *  label,
u8 *  bytes,
int  len,
u8 *  result 
)
+
+
+ +

+The PRF function described in section 6.5 of the WUSB spec. +

+This function concatenates MIC values returned from dwc_cmf() to create a value of the requested length.

+

Parameters:
+ + + + +
prf_len Length of the PRF function in bits (64, 128, or 256).
key,nonce,label,bytes,len Same as for dwc_cmf().
result Byte array to receive the result.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_wusb_fill_ccm_nonce (uint16_t  haddr,
uint16_t  daddr,
uint8_t *  tkid,
uint8_t *  nonce 
)
+
+
+ +

+Fills in CCM Nonce per the WUSB spec. +

+

Parameters:
+ + + + + +
[in] haddr Host address.
[in] daddr Device address.
[in] tkid Session Key(PTK) identifier.
[out] nonce Pointer to where the CCM Nonce output is to be written.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_wusb_gen_nonce (uint16_t  addr,
uint8_t *  nonce 
)
+
+
+ +

+Generates a 16-byte cryptographic-grade random number for the Host/Device Nonce. +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_wusb_gen_key (uint8_t *  ccm_nonce,
uint8_t *  mk,
uint8_t *  hnonce,
uint8_t *  dnonce,
uint8_t *  kck,
uint8_t *  ptk 
)
+
+
+ +

+Generates the Session Key (PTK) and Key Confirmation Key (KCK) per the WUSB spec. +

+

Parameters:
+ + + + + + + +
[in] ccm_nonce Pointer to CCM Nonce.
[in] mk Master Key to derive the session from
[in] hnonce Pointer to Host Nonce.
[in] dnonce Pointer to Device Nonce.
[out] kck Pointer to where the KCK output is to be written.
[out] ptk Pointer to where the PTK output is to be written.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_wusb_gen_mic (uint8_t *  ccm_nonce,
uint8_t *  kck,
uint8_t *  data,
uint8_t *  mic 
)
+
+
+ +

+Generates the Message Integrity Code over the Handshake data per the WUSB spec. +

+

Parameters:
+ + + + + +
ccm_nonce Pointer to CCM Nonce.
kck Pointer to Key Confirmation Key.
data Pointer to Handshake data to be checked.
mic Pointer to where the MIC output is to be written.
+
+ +
+

+


Generated on Tue May 5 02:22:50 2009 for Synopsys DWC Portability and Common Library for UWB by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_common_port/doc/html/dwc__crypto_8h.html b/drivers/usb/host/dwc_common_port/doc/html/dwc__crypto_8h.html new file mode 100644 index 000000000000..12ba7f7ec988 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/dwc__crypto_8h.html @@ -0,0 +1,618 @@ + + +Synopsys DWC Portability and Common Library for UWB: dwc_crypto.h File Reference + + + + + + + +

dwc_crypto.h File Reference


Detailed Description

+This file contains declarations for the WUSB Cryptographic routines as defined in the WUSB spec. +

+They are only to be used internally by the DWC UWB modules. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Functions

int dwc_wusb_aes_encrypt (u8 *src, u8 *key, u8 *dst)
 Encrypts an array of bytes using the AES encryption engine.
void dwc_wusb_cmf (u8 *key, u8 *nonce, char *label, u8 *bytes, int len, u8 *result)
 The CCM-MAC-FUNCTION described in section 6.5 of the WUSB spec.
void dwc_wusb_prf (int prf_len, u8 *key, u8 *nonce, char *label, u8 *bytes, int len, u8 *result)
 The PRF function described in section 6.5 of the WUSB spec.
static void dwc_wusb_prf_64 (u8 *key, u8 *nonce, char *label, u8 *bytes, int len, u8 *result)
 The PRF-64 function described in section 6.5 of the WUSB spec.
static void dwc_wusb_prf_128 (u8 *key, u8 *nonce, char *label, u8 *bytes, int len, u8 *result)
 The PRF-128 function described in section 6.5 of the WUSB spec.
static void dwc_wusb_prf_256 (u8 *key, u8 *nonce, char *label, u8 *bytes, int len, u8 *result)
 The PRF-256 function described in section 6.5 of the WUSB spec.
void dwc_wusb_fill_ccm_nonce (uint16_t haddr, uint16_t daddr, uint8_t *tkid, uint8_t *nonce)
 Fills in CCM Nonce per the WUSB spec.
void dwc_wusb_gen_nonce (uint16_t addr, uint8_t *nonce)
 Generates a 16-byte cryptographic-grade random number for the Host/Device Nonce.
void dwc_wusb_gen_key (uint8_t *ccm_nonce, uint8_t *mk, uint8_t *hnonce, uint8_t *dnonce, uint8_t *kck, uint8_t *ptk)
 Generates the Session Key (PTK) and Key Confirmation Key (KCK) per the WUSB spec.
void dwc_wusb_gen_mic (uint8_t *ccm_nonce, uint8_t *kck, uint8_t *data, uint8_t *mic)
 Generates the Message Integrity Code over the Handshake data per the WUSB spec.
+


Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_wusb_aes_encrypt (u8 *  src,
u8 *  key,
u8 *  dst 
)
+
+
+ +

+Encrypts an array of bytes using the AES encryption engine. +

+If dst == src, then the bytes will be encrypted in-place.

+

Returns:
0 on success, negative error code on error.
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_wusb_cmf (u8 *  key,
u8 *  nonce,
char *  label,
u8 *  bytes,
int  len,
u8 *  result 
)
+
+
+ +

+The CCM-MAC-FUNCTION described in section 6.5 of the WUSB spec. +

+This function takes a data string and returns the encrypted CBC Counter-mode MIC.

+

Parameters:
+ + + + + + + +
key The 128-bit symmetric key.
nonce The CCM nonce.
label The unique 14-byte ASCII text label.
bytes The byte array to be encrypted.
len Length of the byte array.
result Byte array to receive the 8-byte encrypted MIC.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_wusb_prf (int  prf_len,
u8 *  key,
u8 *  nonce,
char *  label,
u8 *  bytes,
int  len,
u8 *  result 
)
+
+
+ +

+The PRF function described in section 6.5 of the WUSB spec. +

+This function concatenates MIC values returned from dwc_cmf() to create a value of the requested length.

+

Parameters:
+ + + + +
prf_len Length of the PRF function in bits (64, 128, or 256).
key,nonce,label,bytes,len Same as for dwc_cmf().
result Byte array to receive the result.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static void dwc_wusb_prf_64 (u8 *  key,
u8 *  nonce,
char *  label,
u8 *  bytes,
int  len,
u8 *  result 
) [inline, static]
+
+
+ +

+The PRF-64 function described in section 6.5 of the WUSB spec. +

+

Parameters:
+ + +
key,nonce,label,bytes,len,result Same as for dwc_prf().
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static void dwc_wusb_prf_128 (u8 *  key,
u8 *  nonce,
char *  label,
u8 *  bytes,
int  len,
u8 *  result 
) [inline, static]
+
+
+ +

+The PRF-128 function described in section 6.5 of the WUSB spec. +

+

Parameters:
+ + +
key,nonce,label,bytes,len,result Same as for dwc_prf().
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static void dwc_wusb_prf_256 (u8 *  key,
u8 *  nonce,
char *  label,
u8 *  bytes,
int  len,
u8 *  result 
) [inline, static]
+
+
+ +

+The PRF-256 function described in section 6.5 of the WUSB spec. +

+

Parameters:
+ + +
key,nonce,label,bytes,len,result Same as for dwc_prf().
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_wusb_fill_ccm_nonce (uint16_t  haddr,
uint16_t  daddr,
uint8_t *  tkid,
uint8_t *  nonce 
)
+
+
+ +

+Fills in CCM Nonce per the WUSB spec. +

+

Parameters:
+ + + + + +
[in] haddr Host address.
[in] daddr Device address.
[in] tkid Session Key(PTK) identifier.
[out] nonce Pointer to where the CCM Nonce output is to be written.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_wusb_gen_nonce (uint16_t  addr,
uint8_t *  nonce 
)
+
+
+ +

+Generates a 16-byte cryptographic-grade random number for the Host/Device Nonce. +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_wusb_gen_key (uint8_t *  ccm_nonce,
uint8_t *  mk,
uint8_t *  hnonce,
uint8_t *  dnonce,
uint8_t *  kck,
uint8_t *  ptk 
)
+
+
+ +

+Generates the Session Key (PTK) and Key Confirmation Key (KCK) per the WUSB spec. +

+

Parameters:
+ + + + + + + +
[in] ccm_nonce Pointer to CCM Nonce.
[in] mk Master Key to derive the session from
[in] hnonce Pointer to Host Nonce.
[in] dnonce Pointer to Device Nonce.
[out] kck Pointer to where the KCK output is to be written.
[out] ptk Pointer to where the PTK output is to be written.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_wusb_gen_mic (uint8_t *  ccm_nonce,
uint8_t *  kck,
uint8_t *  data,
uint8_t *  mic 
)
+
+
+ +

+Generates the Message Integrity Code over the Handshake data per the WUSB spec. +

+

Parameters:
+ + + + + +
ccm_nonce Pointer to CCM Nonce.
kck Pointer to Key Confirmation Key.
data Pointer to Handshake data to be checked.
mic Pointer to where the MIC output is to be written.
+
+ +
+

+


Generated on Tue May 5 02:22:50 2009 for Synopsys DWC Portability and Common Library for UWB by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_common_port/doc/html/dwc__dh_8h.html b/drivers/usb/host/dwc_common_port/doc/html/dwc__dh_8h.html new file mode 100644 index 000000000000..ce0ca7215e63 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/dwc__dh_8h.html @@ -0,0 +1,166 @@ + + +Synopsys DWC Portability and Common Library for UWB: dwc_dh.h File Reference + + + + + + + +

dwc_dh.h File Reference


Detailed Description

+This file defines the common functions on device and host for performing numeric association as defined in the WUSB spec. +

+They are only to be used internally by the DWC UWB modules. +

+ + + + + + + + + + + + + + + +

Functions

+int dwc_dh_sha256 (uint8_t *message, uint32_t len, uint8_t *out)
+int dwc_dh_hmac_sha256 (uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t *out)
+int dwc_dh_modpow (void *num, uint32_t num_len, void *exp, uint32_t exp_len, void *mod, uint32_t mod_len, void *out)
int dwc_dh_pk (uint8_t nd, uint8_t *exp, uint8_t *pkd, uint8_t *hash)
 Computes PKD or PKH, and SHA-256(PKd || Nd).
int dwc_dh_derive_keys (uint8_t nd, uint8_t *pkh, uint8_t *pkd, uint8_t *exp, int is_host, char *dd, uint8_t *ck, uint8_t *kdk)
 Computes the DHKEY, and VD.
+


Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_dh_pk (uint8_t  nd,
uint8_t *  exp,
uint8_t *  pkd,
uint8_t *  hash 
)
+
+
+ +

+Computes PKD or PKH, and SHA-256(PKd || Nd). +

+PK = g^exp mod p.

+Input: Nd = Number of digits on the device.

+Output: exp = A 32-byte buffer to be filled with a randomly generated number. used as either A or B. pk = A 384-byte buffer to be filled with the PKH or PKD. hash = A 32-byte buffer to be filled with SHA-256(PK || ND). +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_dh_derive_keys (uint8_t  nd,
uint8_t *  pkh,
uint8_t *  pkd,
uint8_t *  exp,
int  is_host,
char *  dd,
uint8_t *  ck,
uint8_t *  kdk 
)
+
+
+ +

+Computes the DHKEY, and VD. +

+If called from host, then it will comput DHKEY=PKD^exp % p. If called from device, then it will comput DHKEY=PKH^exp % p.

+Input: pkd = The PKD value. pkh = The PKH value. exp = The A value (if device) or B value (if host) generated in dwc_wudev_dh_pk. is_host = Set to non zero if a WUSB host is calling this function.

+Output:

+dd = A pointer to an buffer to be set to the displayed digits string to be shown to the user. This buffer should be at 5 bytes long to hold 4 digits plus a null termination character. This buffer can be used directly for display. ck = A 16-byte buffer to be filled with the CK. kdk = A 32-byte buffer to be filled with the KDK. +

+

+


Generated on Tue May 5 02:22:50 2009 for Synopsys DWC Portability and Common Library for UWB by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_common_port/doc/html/dwc__list_8h.html b/drivers/usb/host/dwc_common_port/doc/html/dwc__list_8h.html new file mode 100644 index 000000000000..04d7db6148a5 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/dwc__list_8h.html @@ -0,0 +1,1844 @@ + + +Synopsys DWC Portability and Common Library for UWB: dwc_list.h File Reference + + + + + + + +

dwc_list.h File Reference


Detailed Description

+This file defines linked list operations. +

+It is derived from BSD with only the MACRO names being prefixed with DWC_. This is because a few of these names conflict with those on Linux. For documentation on use, see the inline comments in the source code. The original license for this source code applies and is preserved in the dwc_list.h source file. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Structures

struct  dwc_list_link

Defines

#define DWC_LIST_INIT(link)
+#define DWC_LIST_FIRST(link)   ((link)->next)
+#define DWC_LIST_LAST(link)   ((link)->prev)
+#define DWC_LIST_END(link)   (link)
+#define DWC_LIST_NEXT(link)   ((link)->next)
+#define DWC_LIST_PREV(link)   ((link)->prev)
+#define DWC_LIST_EMPTY(link)   (DWC_LIST_FIRST(link) == DWC_LIST_END(link))
#define DWC_LIST_ENTRY(link, type, field)
#define DWC_LIST_INSERT_HEAD(list, link)
#define DWC_LIST_INSERT_TAIL(list, link)
#define DWC_LIST_REMOVE(link)
#define DWC_LIST_REMOVE_INIT(link)
#define DWC_LIST_MOVE_HEAD(list, link)
#define DWC_LIST_MOVE_TAIL(list, link)
#define DWC_LIST_FOREACH(var, list)
#define DWC_LIST_FOREACH_SAFE(var, var2, list)
#define DWC_LIST_FOREACH_REVERSE(var, list)
#define DWC_SLIST_HEAD(name, type)
+#define DWC_SLIST_HEAD_INITIALIZER(head)   { NULL }
#define DWC_SLIST_ENTRY(type)
+#define DWC_SLIST_FIRST(head)   ((head)->slh_first)
+#define DWC_SLIST_END(head)   NULL
+#define DWC_SLIST_EMPTY(head)   (SLIST_FIRST(head) == SLIST_END(head))
+#define DWC_SLIST_NEXT(elm, field)   ((elm)->field.sle_next)
#define DWC_SLIST_FOREACH(var, head, field)
#define DWC_SLIST_FOREACH_PREVPTR(var, varp, head, field)
#define DWC_SLIST_INIT(head)
#define DWC_SLIST_INSERT_AFTER(slistelm, elm, field)
#define DWC_SLIST_INSERT_HEAD(head, elm, field)
#define DWC_SLIST_REMOVE_NEXT(head, elm, field)
#define DWC_SLIST_REMOVE_HEAD(head, field)
#define DWC_SLIST_REMOVE(head, elm, type, field)
#define DWC_SIMPLEQ_HEAD(name, type)
+#define DWC_SIMPLEQ_HEAD_INITIALIZER(head)   { NULL, &(head).sqh_first }
#define DWC_SIMPLEQ_ENTRY(type)
+#define DWC_SIMPLEQ_FIRST(head)   ((head)->sqh_first)
+#define DWC_SIMPLEQ_END(head)   NULL
+#define DWC_SIMPLEQ_EMPTY(head)   (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
+#define DWC_SIMPLEQ_NEXT(elm, field)   ((elm)->field.sqe_next)
#define DWC_SIMPLEQ_FOREACH(var, head, field)
#define DWC_SIMPLEQ_INIT(head)
#define DWC_SIMPLEQ_INSERT_HEAD(head, elm, field)
#define DWC_SIMPLEQ_INSERT_TAIL(head, elm, field)
#define DWC_SIMPLEQ_INSERT_AFTER(head, listelm, elm, field)
#define DWC_SIMPLEQ_REMOVE_HEAD(head, field)
#define DWC_TAILQ_HEAD(name, type)
+#define DWC_TAILQ_HEAD_INITIALIZER(head)   { NULL, &(head).tqh_first }
#define DWC_TAILQ_ENTRY(type)
+#define DWC_TAILQ_FIRST(head)   ((head)->tqh_first)
+#define DWC_TAILQ_END(head)   NULL
+#define DWC_TAILQ_NEXT(elm, field)   ((elm)->field.tqe_next)
+#define DWC_TAILQ_LAST(head, headname)   (*(((struct headname *)((head)->tqh_last))->tqh_last))
+#define DWC_TAILQ_PREV(elm, headname, field)   (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define DWC_TAILQ_EMPTY(head)   (TAILQ_FIRST(head) == TAILQ_END(head))
#define DWC_TAILQ_FOREACH(var, head, field)
#define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field)
#define DWC_TAILQ_INIT(head)
#define DWC_TAILQ_INSERT_HEAD(head, elm, field)
#define DWC_TAILQ_INSERT_TAIL(head, elm, field)
#define DWC_TAILQ_INSERT_AFTER(head, listelm, elm, field)
#define DWC_TAILQ_INSERT_BEFORE(listelm, elm, field)
#define DWC_TAILQ_REMOVE(head, elm, field)
#define DWC_TAILQ_REPLACE(head, elm, elm2, field)
#define DWC_CIRCLEQ_HEAD(name, type)
+#define DWC_CIRCLEQ_HEAD_INITIALIZER(head)   { DWC_CIRCLEQ_END(&head), DWC_CIRCLEQ_END(&head) }
#define DWC_CIRCLEQ_ENTRY(type)
+#define DWC_CIRCLEQ_FIRST(head)   ((head)->cqh_first)
+#define DWC_CIRCLEQ_LAST(head)   ((head)->cqh_last)
+#define DWC_CIRCLEQ_END(head)   ((void *)(head))
+#define DWC_CIRCLEQ_NEXT(elm, field)   ((elm)->field.cqe_next)
+#define DWC_CIRCLEQ_PREV(elm, field)   ((elm)->field.cqe_prev)
+#define DWC_CIRCLEQ_EMPTY(head)   (DWC_CIRCLEQ_FIRST(head) == DWC_CIRCLEQ_END(head))
+#define DWC_CIRCLEQ_EMPTY_ENTRY(elm, field)   (((elm)->field.cqe_next == NULL) && ((elm)->field.cqe_prev == NULL))
#define DWC_CIRCLEQ_FOREACH(var, head, field)
#define DWC_CIRCLEQ_FOREACH_SAFE(var, var2, head, field)
#define DWC_CIRCLEQ_FOREACH_REVERSE(var, head, field)
#define DWC_CIRCLEQ_INIT(head)
#define DWC_CIRCLEQ_INIT_ENTRY(elm, field)
#define DWC_CIRCLEQ_INSERT_AFTER(head, listelm, elm, field)
#define DWC_CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field)
#define DWC_CIRCLEQ_INSERT_HEAD(head, elm, field)
#define DWC_CIRCLEQ_INSERT_TAIL(head, elm, field)
#define DWC_CIRCLEQ_REMOVE(head, elm, field)
#define DWC_CIRCLEQ_REMOVE_INIT(head, elm, field)
#define DWC_CIRCLEQ_REPLACE(head, elm, elm2, field)

Typedefs

+typedef dwc_list_link dwc_list_link_t
+


Define Documentation

+ +
+
+ + + + + + + + + +
#define DWC_LIST_INIT (link   ) 
+
+
+ +

+Value:

do{             \
+        (link)->next = (link);          \
+        (link)->prev = (link);          \
+} while(0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_LIST_ENTRY (link,
type,
field   ) 
+
+
+ +

+Value:

(type *)                \
+        ((uint8_t *)(link) - (size_t)(&((type *)0)->field))
+
+
+

+ +

+
+ + + + + + + + + + + + +
#define DWC_LIST_INSERT_HEAD (list,
link   ) 
+
+
+ +

+Value:

do {                    \
+        (link)->next = (list)->next;                            \
+        (link)->prev = (list);                                  \
+        (list)->next->prev = link;                              \
+        (list)->next = link;                                    \
+} while(0)
+
+
+

+ +

+
+ + + + + + + + + + + + +
#define DWC_LIST_INSERT_TAIL (list,
link   ) 
+
+
+ +

+Value:

do {                    \
+        (link)->next = list;                                    \
+        (link)->prev = (list)->prev;                            \
+        (list)->prev->next = link;                              \
+        (list)->prev = link;                                    \
+} while(0)
+
+
+

+ +

+
+ + + + + + + + + +
#define DWC_LIST_REMOVE (link   ) 
+
+
+ +

+Value:

do {                            \
+        (link)->next->prev = (link)->prev;                      \
+        (link)->prev->next = (link)->next;                      \
+} while(0)
+
+
+

+ +

+
+ + + + + + + + + +
#define DWC_LIST_REMOVE_INIT (link   ) 
+
+
+ +

+Value:

do {                            \
+        DWC_LIST_REMOVE(link);                                  \
+        DWC_LIST_INIT(link);                                    \
+} while(0)
+
+
+

+ +

+
+ + + + + + + + + + + + +
#define DWC_LIST_MOVE_HEAD (list,
link   ) 
+
+
+ +

+Value:

do {                    \
+        DWC_LIST_REMOVE(link);                                  \
+        DWC_LIST_INSERT_HEAD(list, link);                       \
+} while(0)
+
+
+

+ +

+
+ + + + + + + + + + + + +
#define DWC_LIST_MOVE_TAIL (list,
link   ) 
+
+
+ +

+Value:

do {                    \
+        DWC_LIST_REMOVE(link);                                  \
+        DWC_LIST_INSERT_TAIL(list, link);                       \
+} while(0)
+
+
+

+ +

+
+ + + + + + + + + + + + +
#define DWC_LIST_FOREACH (var,
list   ) 
+
+
+ +

+Value:

for((var) = DWC_LIST_FIRST(list);                       \
+            (var) != DWC_LIST_END(list);                        \
+            (var) = DWC_LIST_NEXT(var))
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_LIST_FOREACH_SAFE (var,
var2,
list   ) 
+
+
+ +

+Value:

for((var) = DWC_LIST_FIRST(list), var2 = DWC_LIST_NEXT(var);    \
+            (var) != DWC_LIST_END(list);                        \
+            (var) = (var2), var2 = DWC_LIST_NEXT(var2))
+
+
+

+ +

+
+ + + + + + + + + + + + +
#define DWC_LIST_FOREACH_REVERSE (var,
list   ) 
+
+
+ +

+Value:

for((var) = DWC_LIST_LAST(list);                        \
+            (var) != DWC_LIST_END(list);                        \
+            (var) = DWC_LIST_PREV(var))
+
+
+

+ +

+
+ + + + + + + + + + + + +
#define DWC_SLIST_HEAD (name,
type   ) 
+
+
+ +

+Value:

struct name {                                                           \
+        struct type *slh_first; /* first element */                     \
+}
+
+
+

+ +

+
+ + + + + + + + + +
#define DWC_SLIST_ENTRY (type   ) 
+
+
+ +

+Value:

struct {                                                                \
+        struct type *sle_next;  /* next element */                      \
+}
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_SLIST_FOREACH (var,
head,
field   ) 
+
+
+ +

+Value:

for((var) = SLIST_FIRST(head);                                  \
+            (var) != SLIST_END(head);                                   \
+            (var) = SLIST_NEXT(var, field))
+
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
#define DWC_SLIST_FOREACH_PREVPTR (var,
varp,
head,
field   ) 
+
+
+ +

+Value:

for ((varp) = &SLIST_FIRST((head));                             \
+            ((var) = *(varp)) != SLIST_END(head);                       \
+            (varp) = &SLIST_NEXT((var), field))
+
+
+

+ +

+
+ + + + + + + + + +
#define DWC_SLIST_INIT (head   ) 
+
+
+ +

+Value:

{                                               \
+        SLIST_FIRST(head) = SLIST_END(head);                            \
+}
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_SLIST_INSERT_AFTER (slistelm,
elm,
field   ) 
+
+
+ +

+Value:

do {                    \
+        (elm)->field.sle_next = (slistelm)->field.sle_next;             \
+        (slistelm)->field.sle_next = (elm);                             \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_SLIST_INSERT_HEAD (head,
elm,
field   ) 
+
+
+ +

+Value:

do {                    \
+        (elm)->field.sle_next = (head)->slh_first;                      \
+        (head)->slh_first = (elm);                                      \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_SLIST_REMOVE_NEXT (head,
elm,
field   ) 
+
+
+ +

+Value:

do {                    \
+        (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next;  \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + +
#define DWC_SLIST_REMOVE_HEAD (head,
field   ) 
+
+
+ +

+Value:

do {                            \
+        (head)->slh_first = (head)->slh_first->field.sle_next;          \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
#define DWC_SLIST_REMOVE (head,
elm,
type,
field   ) 
+
+
+ +

+Value:

do {                    \
+        if ((head)->slh_first == (elm)) {                               \
+                SLIST_REMOVE_HEAD((head), field);                       \
+        }                                                               \
+        else {                                                          \
+                struct type *curelm = (head)->slh_first;                \
+                while( curelm->field.sle_next != (elm) )                \
+                        curelm = curelm->field.sle_next;                \
+                curelm->field.sle_next =                                \
+                    curelm->field.sle_next->field.sle_next;             \
+        }                                                               \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + +
#define DWC_SIMPLEQ_HEAD (name,
type   ) 
+
+
+ +

+Value:

struct name {                                                           \
+        struct type *sqh_first; /* first element */                     \
+        struct type **sqh_last; /* addr of last next element */         \
+}
+
+
+

+ +

+
+ + + + + + + + + +
#define DWC_SIMPLEQ_ENTRY (type   ) 
+
+
+ +

+Value:

struct {                                                                \
+        struct type *sqe_next;  /* next element */                      \
+}
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_SIMPLEQ_FOREACH (var,
head,
field   ) 
+
+
+ +

+Value:

for((var) = SIMPLEQ_FIRST(head);                                \
+            (var) != SIMPLEQ_END(head);                                 \
+            (var) = SIMPLEQ_NEXT(var, field))
+
+
+

+ +

+
+ + + + + + + + + +
#define DWC_SIMPLEQ_INIT (head   ) 
+
+
+ +

+Value:

do {                                            \
+        (head)->sqh_first = NULL;                                       \
+        (head)->sqh_last = &(head)->sqh_first;                          \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_SIMPLEQ_INSERT_HEAD (head,
elm,
field   ) 
+
+
+ +

+Value:

do {                    \
+        if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)        \
+                (head)->sqh_last = &(elm)->field.sqe_next;              \
+        (head)->sqh_first = (elm);                                      \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_SIMPLEQ_INSERT_TAIL (head,
elm,
field   ) 
+
+
+ +

+Value:

do {                    \
+        (elm)->field.sqe_next = NULL;                                   \
+        *(head)->sqh_last = (elm);                                      \
+        (head)->sqh_last = &(elm)->field.sqe_next;                      \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
#define DWC_SIMPLEQ_INSERT_AFTER (head,
listelm,
elm,
field   ) 
+
+
+ +

+Value:

do {            \
+        if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+                (head)->sqh_last = &(elm)->field.sqe_next;              \
+        (listelm)->field.sqe_next = (elm);                              \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + +
#define DWC_SIMPLEQ_REMOVE_HEAD (head,
field   ) 
+
+
+ +

+Value:

do {                    \
+        if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
+                (head)->sqh_last = &(head)->sqh_first;                  \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + +
#define DWC_TAILQ_HEAD (name,
type   ) 
+
+
+ +

+Value:

struct name {                                                           \
+        struct type *tqh_first; /* first element */                     \
+        struct type **tqh_last; /* addr of last next element */         \
+}
+
+
+

+ +

+
+ + + + + + + + + +
#define DWC_TAILQ_ENTRY (type   ) 
+
+
+ +

+Value:

struct {                                                                \
+        struct type *tqe_next;  /* next element */                      \
+        struct type **tqe_prev; /* address of previous next element */  \
+}
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_TAILQ_FOREACH (var,
head,
field   ) 
+
+
+ +

+Value:

for((var) = TAILQ_FIRST(head);                                  \
+            (var) != TAILQ_END(head);                                   \
+            (var) = TAILQ_NEXT(var, field))
+
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
#define DWC_TAILQ_FOREACH_REVERSE (var,
head,
headname,
field   ) 
+
+
+ +

+Value:

for((var) = TAILQ_LAST(head, headname);                         \
+            (var) != TAILQ_END(head);                                   \
+            (var) = TAILQ_PREV(var, headname, field))
+
+
+

+ +

+
+ + + + + + + + + +
#define DWC_TAILQ_INIT (head   ) 
+
+
+ +

+Value:

do {                                            \
+        (head)->tqh_first = NULL;                                       \
+        (head)->tqh_last = &(head)->tqh_first;                          \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_TAILQ_INSERT_HEAD (head,
elm,
field   ) 
+
+
+ +

+Value:

do {                    \
+        if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)        \
+                (head)->tqh_first->field.tqe_prev =                     \
+                    &(elm)->field.tqe_next;                             \
+        else                                                            \
+                (head)->tqh_last = &(elm)->field.tqe_next;              \
+        (head)->tqh_first = (elm);                                      \
+        (elm)->field.tqe_prev = &(head)->tqh_first;                     \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_TAILQ_INSERT_TAIL (head,
elm,
field   ) 
+
+
+ +

+Value:

do {                    \
+        (elm)->field.tqe_next = NULL;                                   \
+        (elm)->field.tqe_prev = (head)->tqh_last;                       \
+        *(head)->tqh_last = (elm);                                      \
+        (head)->tqh_last = &(elm)->field.tqe_next;                      \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
#define DWC_TAILQ_INSERT_AFTER (head,
listelm,
elm,
field   ) 
+
+
+ +

+Value:

do {            \
+        if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+                (elm)->field.tqe_next->field.tqe_prev =                 \
+                    &(elm)->field.tqe_next;                             \
+        else                                                            \
+                (head)->tqh_last = &(elm)->field.tqe_next;              \
+        (listelm)->field.tqe_next = (elm);                              \
+        (elm)->field.tqe_prev = &(listelm)->field.tqe_next;             \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_TAILQ_INSERT_BEFORE (listelm,
elm,
field   ) 
+
+
+ +

+Value:

do {                    \
+        (elm)->field.tqe_prev = (listelm)->field.tqe_prev;              \
+        (elm)->field.tqe_next = (listelm);                              \
+        *(listelm)->field.tqe_prev = (elm);                             \
+        (listelm)->field.tqe_prev = &(elm)->field.tqe_next;             \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_TAILQ_REMOVE (head,
elm,
field   ) 
+
+
+ +

+Value:

do {                            \
+        if (((elm)->field.tqe_next) != NULL)                            \
+                (elm)->field.tqe_next->field.tqe_prev =                 \
+                    (elm)->field.tqe_prev;                              \
+        else                                                            \
+                (head)->tqh_last = (elm)->field.tqe_prev;               \
+        *(elm)->field.tqe_prev = (elm)->field.tqe_next;                 \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
#define DWC_TAILQ_REPLACE (head,
elm,
elm2,
field   ) 
+
+
+ +

+Value:

do {                    \
+        if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL)   \
+                (elm2)->field.tqe_next->field.tqe_prev =                \
+                    &(elm2)->field.tqe_next;                            \
+        else                                                            \
+                (head)->tqh_last = &(elm2)->field.tqe_next;             \
+        (elm2)->field.tqe_prev = (elm)->field.tqe_prev;                 \
+        *(elm2)->field.tqe_prev = (elm2);                               \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + +
#define DWC_CIRCLEQ_HEAD (name,
type   ) 
+
+
+ +

+Value:

struct name {                                                           \
+        struct type *cqh_first;         /* first element */             \
+        struct type *cqh_last;          /* last element */              \
+}
+
+
+

+ +

+
+ + + + + + + + + +
#define DWC_CIRCLEQ_ENTRY (type   ) 
+
+
+ +

+Value:

struct {                                                                \
+        struct type *cqe_next;          /* next element */              \
+        struct type *cqe_prev;          /* previous element */          \
+}
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_CIRCLEQ_FOREACH (var,
head,
field   ) 
+
+
+ +

+Value:

for((var) = DWC_CIRCLEQ_FIRST(head);                            \
+            (var) != DWC_CIRCLEQ_END(head);                                     \
+            (var) = DWC_CIRCLEQ_NEXT(var, field))
+
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
#define DWC_CIRCLEQ_FOREACH_SAFE (var,
var2,
head,
field   ) 
+
+
+ +

+Value:

for((var) = DWC_CIRCLEQ_FIRST(head), var2 = DWC_CIRCLEQ_NEXT(var, field);                               \
+            (var) != DWC_CIRCLEQ_END(head);                                     \
+            (var) = var2, var2 = DWC_CIRCLEQ_NEXT(var, field))
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_CIRCLEQ_FOREACH_REVERSE (var,
head,
field   ) 
+
+
+ +

+Value:

for((var) = DWC_CIRCLEQ_LAST(head);                                     \
+            (var) != DWC_CIRCLEQ_END(head);                                     \
+            (var) = DWC_CIRCLEQ_PREV(var, field))
+
+
+

+ +

+
+ + + + + + + + + +
#define DWC_CIRCLEQ_INIT (head   ) 
+
+
+ +

+Value:

do {                                            \
+        (head)->cqh_first = DWC_CIRCLEQ_END(head);                              \
+        (head)->cqh_last = DWC_CIRCLEQ_END(head);                               \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + +
#define DWC_CIRCLEQ_INIT_ENTRY (elm,
field   ) 
+
+
+ +

+Value:

do { \
+        (elm)->field.cqe_next = NULL; \
+        (elm)->field.cqe_prev = NULL; \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
#define DWC_CIRCLEQ_INSERT_AFTER (head,
listelm,
elm,
field   ) 
+
+
+ +

+Value:

do {            \
+        (elm)->field.cqe_next = (listelm)->field.cqe_next;              \
+        (elm)->field.cqe_prev = (listelm);                              \
+        if ((listelm)->field.cqe_next == DWC_CIRCLEQ_END(head))         \
+                (head)->cqh_last = (elm);                               \
+        else                                                            \
+                (listelm)->field.cqe_next->field.cqe_prev = (elm);      \
+        (listelm)->field.cqe_next = (elm);                              \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
#define DWC_CIRCLEQ_INSERT_BEFORE (head,
listelm,
elm,
field   ) 
+
+
+ +

+Value:

do {            \
+        (elm)->field.cqe_next = (listelm);                              \
+        (elm)->field.cqe_prev = (listelm)->field.cqe_prev;              \
+        if ((listelm)->field.cqe_prev == DWC_CIRCLEQ_END(head))         \
+                (head)->cqh_first = (elm);                              \
+        else                                                            \
+                (listelm)->field.cqe_prev->field.cqe_next = (elm);      \
+        (listelm)->field.cqe_prev = (elm);                              \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_CIRCLEQ_INSERT_HEAD (head,
elm,
field   ) 
+
+
+ +

+Value:

do {                    \
+        (elm)->field.cqe_next = (head)->cqh_first;                      \
+        (elm)->field.cqe_prev = DWC_CIRCLEQ_END(head);                  \
+        if ((head)->cqh_last == DWC_CIRCLEQ_END(head))                  \
+                (head)->cqh_last = (elm);                               \
+        else                                                            \
+                (head)->cqh_first->field.cqe_prev = (elm);              \
+        (head)->cqh_first = (elm);                                      \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_CIRCLEQ_INSERT_TAIL (head,
elm,
field   ) 
+
+
+ +

+Value:

do {                    \
+        (elm)->field.cqe_next = DWC_CIRCLEQ_END(head);                  \
+        (elm)->field.cqe_prev = (head)->cqh_last;                       \
+        if ((head)->cqh_first == DWC_CIRCLEQ_END(head))                 \
+                (head)->cqh_first = (elm);                              \
+        else                                                            \
+                (head)->cqh_last->field.cqe_next = (elm);               \
+        (head)->cqh_last = (elm);                                       \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_CIRCLEQ_REMOVE (head,
elm,
field   ) 
+
+
+ +

+Value:

do {                            \
+        if ((elm)->field.cqe_next == DWC_CIRCLEQ_END(head))                     \
+                (head)->cqh_last = (elm)->field.cqe_prev;               \
+        else                                                            \
+                (elm)->field.cqe_next->field.cqe_prev =                 \
+                    (elm)->field.cqe_prev;                              \
+        if ((elm)->field.cqe_prev == DWC_CIRCLEQ_END(head))                     \
+                (head)->cqh_first = (elm)->field.cqe_next;              \
+        else                                                            \
+                (elm)->field.cqe_prev->field.cqe_next =                 \
+                    (elm)->field.cqe_next;                              \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_CIRCLEQ_REMOVE_INIT (head,
elm,
field   ) 
+
+
+ +

+Value:

do { \
+        DWC_CIRCLEQ_REMOVE(head, elm, field); \
+        DWC_CIRCLEQ_INIT_ENTRY(elm, field); \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
#define DWC_CIRCLEQ_REPLACE (head,
elm,
elm2,
field   ) 
+
+
+ +

+Value:

do {                    \
+        if (((elm2)->field.cqe_next = (elm)->field.cqe_next) ==         \
+            DWC_CIRCLEQ_END(head))                                              \
+                (head).cqh_last = (elm2);                               \
+        else                                                            \
+                (elm2)->field.cqe_next->field.cqe_prev = (elm2);        \
+        if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) ==         \
+            DWC_CIRCLEQ_END(head))                                              \
+                (head).cqh_first = (elm2);                              \
+        else                                                            \
+                (elm2)->field.cqe_prev->field.cqe_next = (elm2);        \
+} while (0)
+
+
+

+


Generated on Tue May 5 02:22:50 2009 for Synopsys DWC Portability and Common Library for UWB by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_common_port/doc/html/dwc__modpow_8h.html b/drivers/usb/host/dwc_common_port/doc/html/dwc__modpow_8h.html new file mode 100644 index 000000000000..4f575c9608db --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/dwc__modpow_8h.html @@ -0,0 +1,48 @@ + + +Synopsys DWC Portability and Common Library for UWB: dwc_modpow.h File Reference + + + + + + + +

dwc_modpow.h File Reference


Detailed Description

+This file defines the module exponentiation function which is only used internally by the DWC UWB modules for calculation of PKs during numeric association. +

+The routine is taken from the PUTTY, an open source terminal emulator. The PUTTY License is preserved in the dwc_modpow.c file. +

+ + + + + + + + + + + + +

Typedefs

+typedef uint32_t BignumInt
+typedef uint64_t BignumDblInt
+typedef BignumInt * Bignum

Functions

+Bignum dwc_modpow (Bignum base_in, Bignum exp, Bignum mod)
+


Generated on Tue May 5 02:22:50 2009 for Synopsys DWC Portability and Common Library for UWB by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_common_port/doc/html/dwc__notifier_8h.html b/drivers/usb/host/dwc_common_port/doc/html/dwc__notifier_8h.html new file mode 100644 index 000000000000..f67a0ee022e8 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/dwc__notifier_8h.html @@ -0,0 +1,306 @@ + + +Synopsys DWC Portability and Common Library for UWB: dwc_notifier.h File Reference + + + + + + + +

dwc_notifier.h File Reference


Detailed Description

+A simple implementation of the Observer pattern. +

+Any "module" can register as an observer or notifier. The notion of "module" is abstract and can mean anything used to identify either an observer or notifier. Usually it will be a pointer to a data structure which contains some state, ie an object.

+Before any notifiers can be added, the global notification manager must be brought up with dwc_alloc_notification_manager(). dwc_free_notification_manager() will bring it down and free all resources. These would typically be called upon module load and unload. The notification manager is a single global instance that handles all registered observable modules and observers so this should be done only once.

+A module can be observable by using Notifications to publicize some general information about it's state or operation. It does not care who listens, or even if anyone listens, or what they do with the information. The observable modules do not need to know any information about it's observers or their interface, or their state or data.

+Any module can register to emit Notifications. It should publish a list of notifications that it can emit and their behavior, such as when they will get triggered, and what information will be provided to the observer. Then it should register itself as an observable module. See dwc_register_notifier().

+Any module can observe any observable, registered module, provided it has a handle to the other module and knows what notifications to observe. See dwc_add_observer().

+A function of type dwc_notifier_callback_t is called whenever a notification is triggered with one or more observers observing it. This function is called in it's own process so it may sleep or block if needed. It is guaranteed to be called sometime after the notification has occurred and will be called once per each time the notification is triggered. It will NOT be called in the same process context used to trigger the notification.

+Limitiations

+Keep in mind that Notifications that can be triggered in rapid sucession may schedule too many processes too handle. Be aware of this limitation when designing to use notifications, and only add notifications for appropriate observable information.

+Also Notification callbacks are not synchronous. If you need to synchronize the behavior between module/observer you must use other means. And perhaps that will mean Notifications are not the proper solution. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Typedefs

+typedef dwc_notifier dwc_notifier_t
typedef void(*) dwc_notifier_callback_t (void *object, char *notification, void *observer, void *notification_data, void *user_data)
 The callback function must be of this type.

Functions

void dwc_alloc_notification_manager (void)
 Brings up the notification manager.
void dwc_free_notification_manager (void)
 Brings down the notification manager.
dwc_notifier_t * dwc_register_notifier (void *object)
 This function register an observable module.
void dwc_unregister_notifier (dwc_notifier_t *notifier)
 This function unregister an observable module.
int dwc_add_observer (void *observer, void *object, char *notification, dwc_notifier_callback_t callback, void *user_data)
 Add a module as an observer to the observable module.
int dwc_remove_observer (void *observer)
 Removes the specified observer from all notifications that it is currently observing.
void dwc_notify (dwc_notifier_t *notifier, char *notification, void *notification_data)
 This function triggers a Notification.
+


Typedef Documentation

+ +
+
+ + + + +
typedef void(*) dwc_notifier_callback_t(void *object, char *notification, void *observer, void *notification_data, void *user_data)
+
+
+ +

+The callback function must be of this type. +

+

Parameters:
+ + + + + + +
object This is the object that is being observed.
notification This is the notification that was triggered.
observer This is the observer
notification_data This is notification-specific data that the notifier has included in this notification. The value of this should be published in the documentation of the observable module with the notifications.
user_data This is any custom data that the observer provided when adding itself as an observer to the notification.
+
+ +
+

+


Function Documentation

+ +
+
+ + + + + + + + + +
void dwc_alloc_notification_manager (void   ) 
+
+
+ +

+Brings up the notification manager. +

+ +

+

+ +

+
+ + + + + + + + + +
void dwc_free_notification_manager (void   ) 
+
+
+ +

+Brings down the notification manager. +

+ +

+

+ +

+
+ + + + + + + + + +
dwc_notifier_t* dwc_register_notifier (void *  object  ) 
+
+
+ +

+This function register an observable module. +

+A dwc_notifier_t object is returned to the observable module. This is an opaque object that is used by the observable module to trigger notifications. This object should only be accessible to functions that are authorized to trigger notifications for this module. Observers do not need this object. +

+

+ +

+
+ + + + + + + + + +
void dwc_unregister_notifier (dwc_notifier_t *  notifier  ) 
+
+
+ +

+This function unregister an observable module. +

+All observers have to be removed prior to unregistration. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_add_observer (void *  observer,
void *  object,
char *  notification,
dwc_notifier_callback_t  callback,
void *  user_data 
)
+
+
+ +

+Add a module as an observer to the observable module. +

+The observable module needs to have previously registered with the notification manager.

+

Parameters:
+ + + + + + +
observer The observer module
object The module to observe
notification The notification to observe
callback The callback function to call
user_data Any additional user data to pass into the callback function
+
+ +
+

+ +

+
+ + + + + + + + + +
int dwc_remove_observer (void *  observer  ) 
+
+
+ +

+Removes the specified observer from all notifications that it is currently observing. +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_notify (dwc_notifier_t *  notifier,
char *  notification,
void *  notification_data 
)
+
+
+ +

+This function triggers a Notification. +

+It should be called by the observable module, or any module or library which the observable module allows to trigger notification on it's behalf. Such as the dwc_cc_t.

+dwc_notify is a non-blocking function. Callbacks are scheduled called in their own process context for each trigger. Callbacks can be blocking. dwc_notify can be called from interrupt context if needed. +

+

+


Generated on Tue May 5 02:22:50 2009 for Synopsys DWC Portability and Common Library for UWB by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_common_port/doc/html/dwc__os_8h.html b/drivers/usb/host/dwc_common_port/doc/html/dwc__os_8h.html new file mode 100644 index 000000000000..b7e2fb6ad2b1 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/dwc__os_8h.html @@ -0,0 +1,3090 @@ + + +Synopsys DWC Portability and Common Library for UWB: dwc_os.h File Reference + + + + + + + +

dwc_os.h File Reference


Detailed Description

+DWC portability library, low level os-wrapper functions. +

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Primitive Types and Values

+#define YES   1
+#define NO   0
typedef uint8_t dwc_bool_t
 We define a boolean type for consistency.

Error Codes

+#define DWC_E_INVALID   1001
+#define DWC_E_NO_MEMORY   1002
+#define DWC_E_NO_DEVICE   1003
+#define DWC_E_NOT_SUPPORTED   1004
+#define DWC_E_TIMEOUT   1005
+#define DWC_E_BUSY   1006
+#define DWC_E_AGAIN   1007
+#define DWC_E_RESTART   1008
+#define DWC_E_ABORT   1009
+#define DWC_E_SHUTDOWN   1010
+#define DWC_E_NO_DATA   1011
+#define DWC_E_DISCONNECT   2000
+#define DWC_E_UNKNOWN   3000
+#define DWC_E_NO_STREAM_RES   4001
+#define DWC_E_COMMUNICATION   4002
+#define DWC_E_OVERFLOW   4003
+#define DWC_E_PROTOCOL   4004
+#define DWC_E_IN_PROGRESS   4005
+#define DWC_E_PIPE   4006
+#define DWC_E_IO   4007
+#define DWC_E_NO_SPACE   4008

Tracing/Logging Functions

These function provide the capability to add tracing, debugging, and error messages, as well exceptions as assertions. The WUDEV uses these extensively. These could be logged to the main console, the serial port, an internal buffer, etc. These functions could also be no-op if they are too expensive on your system. By default undefining the DEBUG macro already no-ops some of these functions.

+#define dwc_in_irq   DWC_IN_IRQ
+#define dwc_vprintf   DWC_VPRINTF
+#define dwc_vsnprintf   DWC_VSNPRINTF
+#define dwc_printf   DWC_PRINTF
+#define dwc_sprintf   DWC_SPRINTF
+#define dwc_snprintf   DWC_SNPRINTF
+#define dwc_exception   DWC_EXCEPTION
#define DWC_DEBUG(_format, _args...)   __DWC_DEBUG("DEBUG:%s:%s: " _format "\n", __func__, dwc_irq(), ## _args)
 Prints out a Debug message.
+#define dwc_debug   DWC_DEBUG
#define DWC_INFO(_format, _args...)   DWC_PRINTF("INFO:%s: " _format "\n", dwc_irq(), ## _args)
 Prints out an informative message.
+#define dwc_info   DWC_INFO
#define DWC_WARN(_format, _args...)   __DWC_WARN("WARN:%s:%s:%d: " _format "\n", dwc_irq(), __func__, __LINE__, ## _args)
 Prints out a warning message.
+#define dwc_warn   DWC_WARN
#define DWC_ERROR(_format, _args...)   __DWC_ERROR("ERROR:%s:%s:%d: " _format "\n", dwc_irq(), __func__, __LINE__, ## _args)
 Prints out an error message.
+#define dwc_error   DWC_ERROR
+#define DWC_PROTO_ERROR(_format, _args...)   __DWC_WARN("ERROR:%s:%s:%d: " _format "\n", dwc_irq(), __func__, __LINE__, ## _args)
+#define dwc_proto_error   DWC_PROTO_ERROR
#define DWC_ASSERT(_expr, _format, _args...)   if (!(_expr)) { DWC_EXCEPTION("%s:%s:%d: " _format "\n", dwc_irq(), __FILE__, __LINE__, ## _args); }
 Prints out a exception error message if the _expr expression fails.
+#define dwc_assert   DWC_ASSERT
dwc_bool_t DWC_IN_IRQ (void)
 Returns non-zero if in interrupt context.
static char * dwc_irq (void)
 Returns "IRQ" if DWC_IN_IRQ is true.
void DWC_VPRINTF (char *format, va_list args)
 A vprintf() clone.
int DWC_VSNPRINTF (char *str, int size, char *format, va_list args)
 A vsnprintf() clone.
void DWC_PRINTF (char *format,...)
 printf() clone.
int DWC_SPRINTF (char *string, char *format,...)
 sprintf() clone.
int DWC_SNPRINTF (char *string, int size, char *format,...)
 snprintf() clone.
void __DWC_WARN (char *format,...)
 Prints a WARNING message.
void __DWC_ERROR (char *format,...)
 Prints an error message.
void DWC_EXCEPTION (char *format,...)
 Prints an exception error message and takes some user-defined action such as print out a backtrace or trigger a breakpoint.
void __DWC_DEBUG (char *format,...)
 Prints out a debug message.

Byter Ordering

The following functions are for conversions between processor's byte ordering and specific ordering you want.

+#define dwc_cpu_to_le32   DWC_CPU_TO_LE32
+#define dwc_cpu_to_be32   DWC_CPU_TO_BE32
+#define dwc_le32_to_cpu   DWC_LE32_TO_CPU
+#define dwc_be32_to_cpu   DWC_BE32_TO_CPU
+#define dwc_cpu_to_le16   DWC_CPU_TO_LE16
+#define dwc_cpu_to_be16   DWC_CPU_TO_BE16
+#define dwc_le16_to_cpu   DWC_LE16_TO_CPU
+#define dwc_be16_to_cpu   DWC_BE16_TO_CPU
uint32_t DWC_CPU_TO_LE32 (void *p)
 Converts 32 bit data in CPU byte ordering to little endian.
uint32_t DWC_CPU_TO_BE32 (void *p)
 Converts 32 bit data in CPU byte orderint to big endian.
uint32_t DWC_LE32_TO_CPU (void *p)
 Converts 32 bit little endian data to CPU byte ordering.
uint32_t DWC_BE32_TO_CPU (void *p)
 Converts 32 bit big endian data to CPU byte ordering.
uint16_t DWC_CPU_TO_LE16 (void *p)
 Converts 16 bit data in CPU byte ordering to little endian.
uint16_t DWC_CPU_TO_BE16 (void *p)
 Converts 16 bit data in CPU byte orderint to big endian.
uint16_t DWC_LE16_TO_CPU (void *p)
 Converts 16 bit little endian data to CPU byte ordering.
uint16_t DWC_BE16_TO_CPU (void *p)
 Converts 16 bit bi endian data to CPU byte ordering.

Register Read/Write

The following five functions should be implemented to read/write registers of 32-bit and 64-bit sizes. All modules use this to read/write register values. The reg value is a pointer to the register calculated from the void *base variable passed into the driver when it is started.

+#define dwc_read_reg32   DWC_READ_REG32
+#define dwc_read_reg64   DWC_READ_REG64
+#define dwc_write_reg32   DWC_WRITE_REG32
+#define dwc_write_reg64   DWC_WRITE_REG64
+#define dwc_modify_reg32   DWC_MODIFY_REG32
uint32_t DWC_READ_REG32 (uint32_t volatile *reg)
 Reads the content of a 32-bit register.
uint64_t DWC_READ_REG64 (uint64_t volatile *reg)
 Reads the content of a 64-bit register.
void DWC_WRITE_REG32 (uint32_t volatile *reg, uint32_t value)
 Writes to a 32-bit register.
void DWC_WRITE_REG64 (uint64_t volatile *reg, uint64_t value)
 Writes to a 64-bit register.
void DWC_MODIFY_REG32 (uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask)
 Modify bit values in a register.

Crypto Functions

These are the low-level cryptographic functions used by the driver.

+#define dwc_aes_cbc   DWC_AES_CBC
+#define dwc_random_bytes   DWC_RANDOM_BYTES
+#define dwc_sha256   DWC_SHA256
+#define dwc_hmac_sha256   DWC_HMAC_SHA256
int DWC_AES_CBC (uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out)
 Perform AES CBC.
void DWC_RANDOM_BYTES (uint8_t *buffer, uint32_t length)
 Fill the provided buffer with random bytes.
int DWC_SHA256 (uint8_t *message, uint32_t len, uint8_t *out)
 Perform the SHA-256 hash function.
int DWC_HMAC_SHA256 (uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t *out)
 Calculated the HMAC-SHA256.

Memory Allocation

These function provide access to memory allocation. There are only 2 DMA functions and 3 Regular memory functions that need to be implemented. None of the memory debugging routines need to be implemented. The allocation routines all ZERO the contents of the memory.

+Defining DEBUG_MEMORY turns on memory debugging and statistic gathering. This checks for memory leaks, keeping track of alloc/free pairs. It also keeps track of how much memory the driver is using at any given time.

+#define DWC_PAGE_SIZE   4096
+#define DWC_PAGE_OFFSET(addr)   (((uint32_t)addr) & 0xfff)
+#define DWC_PAGE_ALIGNED(addr)   ((((uint32_t)addr) & 0xfff) == 0)
+#define DWC_INVALID_DMA_ADDR   0x0
+#define DWC_ALLOC(_size_)   (dwc_alloc_debug(_size_, __func__, __LINE__))
+#define DWC_ALLOC_ATOMIC(_size_)   (dwc_alloc_atomic_debug(_size_, __func__, __LINE__))
+#define DWC_FREE(_addr_)   (dwc_free_debug(_addr_, __func__, __LINE__))
+#define DWC_DMA_ALLOC(_size_, _dma_)   dwc_dma_alloc_debug(_size_, _dma_, __func__, __LINE__)
+#define DWC_DMA_FREE(_size_, _virt_, _dma_)   dwc_dma_free_debug(_size_, _virt_, _dma_, __func__, __LINE__)
+#define dwc_alloc   DWC_ALLOC
+#define dwc_alloc_atomic   DWC_ALLOC_ATOMIC
+#define dwc_free   DWC_FREE
+#define dwc_dma_alloc   DWC_DMA_ALLOC
+#define dwc_dma_free   DWC_DMA_FREE
+typedef uint32_t dwc_dma_t
void * __DWC_DMA_ALLOC (uint32_t size, dwc_dma_t *dma_addr)
 Allocates a DMA capable buffer and zeroes its contents.
void __DWC_DMA_FREE (uint32_t size, void *virt_addr, dwc_dma_t dma_addr)
 Frees a previosly allocated buffer.
void * __DWC_ALLOC (uint32_t size)
 Allocates a block of memory and zeroes its contents.
void * __DWC_ALLOC_ATOMIC (uint32_t size)
 Allocates a block of memory and zeroes its contents, in an atomic manner which can be used inside interrupt context.
void __DWC_FREE (void *addr)
 Frees a previously allocated buffer.
+void * dwc_alloc_debug (uint32_t size, char const *func, int line)
+void * dwc_alloc_atomic_debug (uint32_t size, char const *func, int line)
+void dwc_free_debug (void *addr, char const *func, int line)
+void * dwc_dma_alloc_debug (uint32_t size, dwc_dma_t *dma_addr, char const *func, int line)
+void dwc_dma_free_debug (uint32_t size, void *virt_addr, dwc_dma_t dma_addr, char const *func, int line)
+void dwc_memory_debug_start (void)
+void dwc_memory_debug_stop (void)
+void dwc_memory_debug_report (void)

Memory and String Processing

+#define dwc_memset   DWC_MEMSET
+#define dwc_memcpy   DWC_MEMCPY
+#define dwc_memmove   DWC_MEMMOVE
+#define dwc_memcmp   DWC_MEMCMP
+#define dwc_strcmp   DWC_STRCMP
+#define dwc_strncmp   DWC_STRNCMP
+#define dwc_strlen   DWC_STRLEN
+#define dwc_strcpy   DWC_STRCPY
+#define dwc_strdup   DWC_STRDUP
+#define dwc_atoi   DWC_ATOI
+#define dwc_atoui   DWC_ATOUI
+#define dwc_utf8_to_utf16le   DWC_UTF8_TO_UTF16LE
void * DWC_MEMSET (void *dest, uint8_t byte, uint32_t size)
 memset() clone
void * DWC_MEMCPY (void *dest, void const *src, uint32_t size)
 memcpy() clone
void * DWC_MEMMOVE (void *dest, void *src, uint32_t size)
 memmove() clone
int DWC_MEMCMP (void *m1, void *m2, uint32_t size)
 memcmp() clone
int DWC_STRCMP (void *s1, void *s2)
 strcmp() clone
int DWC_STRNCMP (void *s1, void *s2, uint32_t size)
 strncmp() clone
int DWC_STRLEN (char const *str)
 strlen() clone, for NULL terminated ASCII strings
char * DWC_STRCPY (char *to, const char *from)
 strcpy() clone, for NULL terminated ASCII strings
char * DWC_STRDUP (char const *str)
 strdup() clone.
int DWC_ATOI (char *str, int32_t *value)
 NOT an atoi() clone.
int DWC_ATOUI (char *str, uint32_t *value)
 Same as above but for unsigned.
int DWC_UTF8_TO_UTF16LE (uint8_t const *utf8string, uint16_t *utf16string, unsigned len)
 This routine returns a UTF16LE unicode encoded string from a UTF8 string.

Wait queues

Wait queues provide a means of synchronizing between threads or processes. A process can block on a waitq if some condition is not true, waiting for it to become true. When the waitq is triggered all waiting process will get unblocked and the condition will be check again. Waitqs should be triggered every time a condition can potentially change.

+#define dwc_waitq_alloc   DWC_WAITQ_ALLOC
+#define dwc_waitq_free   DWC_WAITQ_FREE
+#define dwc_waitq_wait   DWC_WAITQ_WAIT;
+#define dwc_waitq_wait_timeout   DWC_WAITQ_WAIT_TIMEOUT
+#define dwc_waitq_trigger   DWC_WAITQ_TRIGGER
+#define dwc_waitq_abort   DWC_WAITQ_ABORT
+typedef dwc_waitq dwc_waitq_t
typedef int(*) dwc_waitq_condition_t (void *data)
 The type of waitq condition callback function.
dwc_waitq_t * DWC_WAITQ_ALLOC (void)
 Allocate a waitq.
void DWC_WAITQ_FREE (dwc_waitq_t *wq)
 Free a waitq.
int32_t DWC_WAITQ_WAIT (dwc_waitq_t *wq, dwc_waitq_condition_t condition, void *data)
 Check the condition and if it is false, block on the waitq.
int32_t DWC_WAITQ_WAIT_TIMEOUT (dwc_waitq_t *wq, dwc_waitq_condition_t condition, void *data, int32_t msecs)
 Check the condition and if it is false, block on the waitq.
void DWC_WAITQ_TRIGGER (dwc_waitq_t *wq)
 Trigger a waitq, unblocking all processes.
void DWC_WAITQ_ABORT (dwc_waitq_t *wq)
 Unblock all processes waiting on the waitq with an ABORTED result.

Threads

A thread must be explicitly stopped. It must check DWC_THREAD_SHOULD_STOP whenever it is woken up, and then return. The DWC_THREAD_STOP function returns the value from the thread.

+#define dwc_thread_run   DWC_THREAD_RUN
+#define dwc_thread_stop   DWC_THREAD_STOP
+#define dwc_thread_should_stop   DWC_THREAD_SHOULD_STOP
+typedef dwc_thread dwc_thread_t
typedef int(*) dwc_thread_function_t (void *data)
 The thread function.
dwc_thread_t * DWC_THREAD_RUN (dwc_thread_function_t thread_function, char *name, void *data)
 Create a thread and start it running the thread_function.
int DWC_THREAD_STOP (dwc_thread_t *thread)
 Stops a thread.
dwc_bool_t DWC_THREAD_SHOULD_STOP (void)
 Signifies to the thread that it must stop.

Work queues

Workqs are used to queue a callback function to be called at some later time, in another thread.

+#define dwc_workq_alloc   DWC_WORKQ_ALLOC
+#define dwc_workq_free   DWC_WORKQ_FREE
+#define dwc_workq_schedule   DWC_WORKQ_SCHEDULE
+#define dwc_workq_schedule_delayed   DWC_WORKQ_SCHEDULE_DELAYED
+#define dwc_workq_pending   DWC_WORKQ_PENDING
+#define dwc_workq_wait_work_done   DWC_WORKQ_WAIT_WORK_DONE
+typedef dwc_workq dwc_workq_t
typedef void(*) dwc_work_callback_t (void *data)
 The type of the callback function to be called.
dwc_workq_t * DWC_WORKQ_ALLOC (char *name)
 Allocate a workq.
void DWC_WORKQ_FREE (dwc_workq_t *workq)
 Free a workq.
void DWC_WORKQ_SCHEDULE (dwc_workq_t *workq, dwc_work_callback_t work_cb, void *data, char *format,...)
 Schedule a callback on the workq, passing in data.
void DWC_WORKQ_SCHEDULE_DELAYED (dwc_workq_t *workq, dwc_work_callback_t work_cb, void *data, uint32_t time, char *format,...)
 Schedule a callback on the workq, that will be called until at least given number miliseconds have passed.
int DWC_WORKQ_PENDING (dwc_workq_t *workq)
 The number of processes in the workq.
int DWC_WORKQ_WAIT_WORK_DONE (dwc_workq_t *workq, int timeout)
 Blocks until all the work in the workq is complete or timed out.

Tasklets

+#define dwc_task_alloc   DWC_TASK_ALLOC
+#define dwc_task_free   DWC_TASK_FREE
+#define dwc_task_schedule   DWC_TASK_SCHEDULE
+typedef dwc_tasklet dwc_tasklet_t
+typedef void(*) dwc_tasklet_callback_t (void *data)
+dwc_tasklet_t * DWC_TASK_ALLOC (dwc_tasklet_callback_t cb, void *data)
+void DWC_TASK_FREE (dwc_tasklet_t *t)
+void DWC_TASK_SCHEDULE (dwc_tasklet_t *task)

Timer

Callbacks must be small and atomic.

+#define dwc_timer_alloc   DWC_TIMER_ALLOC
+#define dwc_timer_free   DWC_TIMER_FREE
+#define dwc_timer_schedule   DWC_TIMER_SCHEDULE
+#define dwc_timer_cancel   DWC_TIMER_CANCEL
+typedef dwc_timer dwc_timer_t
+typedef void(*) dwc_timer_callback_t (void *data)
+dwc_timer_t * DWC_TIMER_ALLOC (char *name, dwc_timer_callback_t cb, void *data)
+void DWC_TIMER_FREE (dwc_timer_t *timer)
void DWC_TIMER_SCHEDULE (dwc_timer_t *timer, uint32_t time)
 Schedules the timer to run at time ms from now.
void DWC_TIMER_CANCEL (dwc_timer_t *timer)
 Disables the timer from execution.

Spinlocks

These locks are used when the work between the lock/unlock is atomic and short. Interrupts are also disabled during the lock/unlock and thus they are suitable to lock between interrupt/non-interrupt context. They also lock between processes if you have multiple CPUs or Preemption. If you don't have multiple CPUS or Preemption, then the you can simply implement the DWC_SPINLOCK and DWC_SPINUNLOCK to disable and enable interrupts. Because the work between the lock/unlock is atomic, the process context will never change, and so you never have to lock between processes.

+#define dwc_spinlock_alloc   DWC_SPINLOCK_ALLOC
+#define dwc_spinlock_free   DWC_SPINLOCK_FREE
+#define dwc_spinlock_irqsave   DWC_SPINLOCK_IRQSAVE
+#define dwc_spinunlock_irqrestore   DWC_SPINUNLOCK_IRQRESTORE
+#define dwc_spinlock   DWC_SPINLOCK
+#define dwc_spinunlock   DWC_SPINUNLOCK
+typedef dwc_spinlock dwc_spinlock_t
dwc_spinlock_t * DWC_SPINLOCK_ALLOC (void)
 Returns an initialized lock variable.
void DWC_SPINLOCK_FREE (dwc_spinlock_t *lock)
 Frees an initialized lock variable.
void DWC_SPINLOCK_IRQSAVE (dwc_spinlock_t *lock, uint64_t *flags)
 Disables interrupts and blocks until it acquires the lock.
void DWC_SPINUNLOCK_IRQRESTORE (dwc_spinlock_t *lock, uint64_t flags)
 Re-enables the interrupt and releases the lock.
void DWC_SPINLOCK (dwc_spinlock_t *lock)
 Blocks until it acquires the lock.
void DWC_SPINUNLOCK (dwc_spinlock_t *lock)
 Releases the lock.

Mutexes

Unlike spinlocks Mutexes lock only between processes and the work between the lock/unlock CAN block, therefore it CANNOT be called from interrupt context.

+#define dwc_mutex_alloc   DWC_MUTEX_ALLOC
+#define dwc_mutex_free   DWC_MUTEX_FREE
+#define dwc_mutex_lock   DWC_MUTEX_LOCK
+#define dwc_mutex_trylock   DWC_MUTEX_TRYLOCK
+#define dwc_mutex_unlock   DWC_MUTEX_UNLOCK
+typedef dwc_mutex dwc_mutex_t
+dwc_mutex_t * DWC_MUTEX_ALLOC (void)
+void DWC_MUTEX_FREE (dwc_mutex_t *mutex)
+void DWC_MUTEX_LOCK (dwc_mutex_t *mutex)
int DWC_MUTEX_TRYLOCK (dwc_mutex_t *mutex)
 Non-blocking lock returns 1 on successful lock.
+void DWC_MUTEX_UNLOCK (dwc_mutex_t *mutex)

Time

+#define dwc_udelay   DWC_UDELAY
+#define dwc_mdelay   DWC_MDELAY
+#define dwc_msleep   DWC_MSLEEP
+#define dwc_time   DWC_TIME
void DWC_UDELAY (uint32_t usecs)
 Microsecond delay.
void DWC_MDELAY (uint32_t msecs)
 Millisecond delay.
void DWC_MSLEEP (uint32_t msecs)
 Non-busy waiting.
+uint32_t DWC_TIME (void)
+


Define Documentation

+ +
+
+ + + + + + + + + + + + +
#define DWC_DEBUG (_format,
_args...   )    __DWC_DEBUG("DEBUG:%s:%s: " _format "\n", __func__, dwc_irq(), ## _args)
+
+
+ +

+Prints out a Debug message. +

+ +

+

+ +

+
+ + + + + + + + + + + + +
#define DWC_INFO (_format,
_args...   )    DWC_PRINTF("INFO:%s: " _format "\n", dwc_irq(), ## _args)
+
+
+ +

+Prints out an informative message. +

+ +

+

+ +

+
+ + + + + + + + + + + + +
#define DWC_WARN (_format,
_args...   )    __DWC_WARN("WARN:%s:%s:%d: " _format "\n", dwc_irq(), __func__, __LINE__, ## _args)
+
+
+ +

+Prints out a warning message. +

+ +

+

+ +

+
+ + + + + + + + + + + + +
#define DWC_ERROR (_format,
_args...   )    __DWC_ERROR("ERROR:%s:%s:%d: " _format "\n", dwc_irq(), __func__, __LINE__, ## _args)
+
+
+ +

+Prints out an error message. +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_ASSERT (_expr,
_format,
_args...   )    if (!(_expr)) { DWC_EXCEPTION("%s:%s:%d: " _format "\n", dwc_irq(), __FILE__, __LINE__, ## _args); }
+
+
+ +

+Prints out a exception error message if the _expr expression fails. +

+Disabled if DEBUG is not enabled. +

+

+


Typedef Documentation

+ +
+
+ + + + +
typedef uint8_t dwc_bool_t
+
+
+ +

+We define a boolean type for consistency. +

+Can be either YES or NO +

+

+ +

+
+ + + + +
typedef int(*) dwc_waitq_condition_t(void *data)
+
+
+ +

+The type of waitq condition callback function. +

+This is called every time condition is evaluated. +

+

+ +

+
+ + + + +
typedef int(*) dwc_thread_function_t(void *data)
+
+
+ +

+The thread function. +

+ +

+

+ +

+
+ + + + +
typedef void(*) dwc_work_callback_t(void *data)
+
+
+ +

+The type of the callback function to be called. +

+ +

+

+


Function Documentation

+ +
+
+ + + + + + + + + +
dwc_bool_t DWC_IN_IRQ (void   ) 
+
+
+ +

+Returns non-zero if in interrupt context. +

+ +

+

+ +

+
+ + + + + + + + + +
static char* dwc_irq (void   )  [inline, static]
+
+
+ +

+Returns "IRQ" if DWC_IN_IRQ is true. +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void DWC_VPRINTF (char *  format,
va_list  args 
)
+
+
+ +

+A vprintf() clone. +

+Just call vprintf if you've got it. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int DWC_VSNPRINTF (char *  str,
int  size,
char *  format,
va_list  args 
)
+
+
+ +

+A vsnprintf() clone. +

+Just call vprintf if you've got it. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void DWC_PRINTF (char *  format,
  ... 
)
+
+
+ +

+printf() clone. +

+Just call printf if you've go it. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int DWC_SPRINTF (char *  string,
char *  format,
  ... 
)
+
+
+ +

+sprintf() clone. +

+Just call sprintf if you've got it. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int DWC_SNPRINTF (char *  string,
int  size,
char *  format,
  ... 
)
+
+
+ +

+snprintf() clone. +

+Just call snprintf if you've got it. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void __DWC_WARN (char *  format,
  ... 
)
+
+
+ +

+Prints a WARNING message. +

+On systems that don't differentiate between warnings and regular log messages, just print it. Indicates that something may be wrong with the driver. Works like printf().

+Use the DWC_WARN macro to call this function. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void __DWC_ERROR (char *  format,
  ... 
)
+
+
+ +

+Prints an error message. +

+On systems that don't differentiate between errors and regular log messages, just print it. Indicates that something went wrong with the driver, but it can be recovered from. Works like printf().

+Use the DWC_ERROR macro to call this function. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void DWC_EXCEPTION (char *  format,
  ... 
)
+
+
+ +

+Prints an exception error message and takes some user-defined action such as print out a backtrace or trigger a breakpoint. +

+Indicates that something went abnormally wrong with the driver such as programmer error, or other exceptional condition. It should not be ignored so even on systems without printing capability, some action should be taken to notify the developer of it. Works like printf(). +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void __DWC_DEBUG (char *  format,
  ... 
)
+
+
+ +

+Prints out a debug message. +

+Used for logging/trace messages.

+Use the DWC_DEBUG macro to call this function +

+

+ +

+
+ + + + + + + + + +
uint32_t DWC_CPU_TO_LE32 (void *  p  ) 
+
+
+ +

+Converts 32 bit data in CPU byte ordering to little endian. +

+ +

+

+ +

+
+ + + + + + + + + +
uint32_t DWC_CPU_TO_BE32 (void *  p  ) 
+
+
+ +

+Converts 32 bit data in CPU byte orderint to big endian. +

+ +

+

+ +

+
+ + + + + + + + + +
uint32_t DWC_LE32_TO_CPU (void *  p  ) 
+
+
+ +

+Converts 32 bit little endian data to CPU byte ordering. +

+ +

+

+ +

+
+ + + + + + + + + +
uint32_t DWC_BE32_TO_CPU (void *  p  ) 
+
+
+ +

+Converts 32 bit big endian data to CPU byte ordering. +

+ +

+

+ +

+
+ + + + + + + + + +
uint16_t DWC_CPU_TO_LE16 (void *  p  ) 
+
+
+ +

+Converts 16 bit data in CPU byte ordering to little endian. +

+ +

+

+ +

+
+ + + + + + + + + +
uint16_t DWC_CPU_TO_BE16 (void *  p  ) 
+
+
+ +

+Converts 16 bit data in CPU byte orderint to big endian. +

+ +

+

+ +

+
+ + + + + + + + + +
uint16_t DWC_LE16_TO_CPU (void *  p  ) 
+
+
+ +

+Converts 16 bit little endian data to CPU byte ordering. +

+ +

+

+ +

+
+ + + + + + + + + +
uint16_t DWC_BE16_TO_CPU (void *  p  ) 
+
+
+ +

+Converts 16 bit bi endian data to CPU byte ordering. +

+ +

+

+ +

+
+ + + + + + + + + +
uint32_t DWC_READ_REG32 (uint32_t volatile *  reg  ) 
+
+
+ +

+Reads the content of a 32-bit register. +

+ +

+

+ +

+
+ + + + + + + + + +
uint64_t DWC_READ_REG64 (uint64_t volatile *  reg  ) 
+
+
+ +

+Reads the content of a 64-bit register. +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void DWC_WRITE_REG32 (uint32_t volatile *  reg,
uint32_t  value 
)
+
+
+ +

+Writes to a 32-bit register. +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void DWC_WRITE_REG64 (uint64_t volatile *  reg,
uint64_t  value 
)
+
+
+ +

+Writes to a 64-bit register. +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void DWC_MODIFY_REG32 (uint32_t volatile *  reg,
uint32_t  clear_mask,
uint32_t  set_mask 
)
+
+
+ +

+Modify bit values in a register. +

+Using the algorithm: (reg_contents & ~clear_mask) | set_mask. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int DWC_AES_CBC (uint8_t *  message,
uint32_t  messagelen,
uint8_t *  key,
uint32_t  keylen,
uint8_t  iv[16],
uint8_t *  out 
)
+
+
+ +

+Perform AES CBC. +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void DWC_RANDOM_BYTES (uint8_t *  buffer,
uint32_t  length 
)
+
+
+ +

+Fill the provided buffer with random bytes. +

+These should be cryptographic grade random numbers. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int DWC_SHA256 (uint8_t *  message,
uint32_t  len,
uint8_t *  out 
)
+
+
+ +

+Perform the SHA-256 hash function. +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int DWC_HMAC_SHA256 (uint8_t *  message,
uint32_t  messagelen,
uint8_t *  key,
uint32_t  keylen,
uint8_t *  out 
)
+
+
+ +

+Calculated the HMAC-SHA256. +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void* __DWC_DMA_ALLOC (uint32_t  size,
dwc_dma_t *  dma_addr 
)
+
+
+ +

+Allocates a DMA capable buffer and zeroes its contents. +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void __DWC_DMA_FREE (uint32_t  size,
void *  virt_addr,
dwc_dma_t  dma_addr 
)
+
+
+ +

+Frees a previosly allocated buffer. +

+ +

+

+ +

+
+ + + + + + + + + +
void* __DWC_ALLOC (uint32_t  size  ) 
+
+
+ +

+Allocates a block of memory and zeroes its contents. +

+ +

+

+ +

+
+ + + + + + + + + +
void* __DWC_ALLOC_ATOMIC (uint32_t  size  ) 
+
+
+ +

+Allocates a block of memory and zeroes its contents, in an atomic manner which can be used inside interrupt context. +

+The size should be sufficiently small, a few KB at most, such that failures are not likely to occur. Can just call __DWC_ALLOC if it is atomic. +

+

+ +

+
+ + + + + + + + + +
void __DWC_FREE (void *  addr  ) 
+
+
+ +

+Frees a previously allocated buffer. +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void* DWC_MEMSET (void *  dest,
uint8_t  byte,
uint32_t  size 
)
+
+
+ +

+memset() clone +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void* DWC_MEMCPY (void *  dest,
void const *  src,
uint32_t  size 
)
+
+
+ +

+memcpy() clone +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void* DWC_MEMMOVE (void *  dest,
void *  src,
uint32_t  size 
)
+
+
+ +

+memmove() clone +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int DWC_MEMCMP (void *  m1,
void *  m2,
uint32_t  size 
)
+
+
+ +

+memcmp() clone +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int DWC_STRCMP (void *  s1,
void *  s2 
)
+
+
+ +

+strcmp() clone +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int DWC_STRNCMP (void *  s1,
void *  s2,
uint32_t  size 
)
+
+
+ +

+strncmp() clone +

+ +

+

+ +

+
+ + + + + + + + + +
int DWC_STRLEN (char const *  str  ) 
+
+
+ +

+strlen() clone, for NULL terminated ASCII strings +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
char* DWC_STRCPY (char *  to,
const char *  from 
)
+
+
+ +

+strcpy() clone, for NULL terminated ASCII strings +

+ +

+

+ +

+
+ + + + + + + + + +
char* DWC_STRDUP (char const *  str  ) 
+
+
+ +

+strdup() clone. +

+If you wish to use memory allocation debugging, this implementation of strdup should use the DWC_* memory routines instead of calling a predefined strdup. Otherwise the memory allocated by this routine will not be seen by the debugging routines. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int DWC_ATOI (char *  str,
int32_t *  value 
)
+
+
+ +

+NOT an atoi() clone. +

+Read the description carefully. Returns an integer converted from the string str in base 10 unless the string begins with a "0x" in which case it is base 16. String must be a NULL terminated sequence of ASCII characters and may optionally begin with whitespace, a + or -, and a "0x" prefix if base 16. The remaining characters must be valid digits for the number and end with a NULL character. If any invalid characters are encountered or it returns with a negative error code and the results of the conversion are undefined. On sucess it returns 0. Overflow conditions are undefined. An example implementation using atoi() can be referenced from the Linux implementation. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int DWC_ATOUI (char *  str,
uint32_t *  value 
)
+
+
+ +

+Same as above but for unsigned. +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int DWC_UTF8_TO_UTF16LE (uint8_t const *  utf8string,
uint16_t *  utf16string,
unsigned  len 
)
+
+
+ +

+This routine returns a UTF16LE unicode encoded string from a UTF8 string. +

+ +

+

+ +

+
+ + + + + + + + + +
dwc_waitq_t* DWC_WAITQ_ALLOC (void   ) 
+
+
+ +

+Allocate a waitq. +

+ +

+

+ +

+
+ + + + + + + + + +
void DWC_WAITQ_FREE (dwc_waitq_t *  wq  ) 
+
+
+ +

+Free a waitq. +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int32_t DWC_WAITQ_WAIT (dwc_waitq_t *  wq,
dwc_waitq_condition_t  condition,
void *  data 
)
+
+
+ +

+Check the condition and if it is false, block on the waitq. +

+When unblocked, check the condition again. The function returns when the condition becomes true. The return value is 0 on condition true, DWC_WAITQ_ABORTED on abort or killed, or DWC_WAITQ_UNKNOWN on error. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int32_t DWC_WAITQ_WAIT_TIMEOUT (dwc_waitq_t *  wq,
dwc_waitq_condition_t  condition,
void *  data,
int32_t  msecs 
)
+
+
+ +

+Check the condition and if it is false, block on the waitq. +

+When unblocked, check the condition again. The function returns when the condition become true or the timeout has passed. The return value is 0 on condition true or DWC_TIMED_OUT on timeout, or DWC_WAITQ_ABORTED, or DWC_WAITQ_UNKNOWN on error. +

+

+ +

+
+ + + + + + + + + +
void DWC_WAITQ_TRIGGER (dwc_waitq_t *  wq  ) 
+
+
+ +

+Trigger a waitq, unblocking all processes. +

+This should be called whenever a condition has potentially changed. +

+

+ +

+
+ + + + + + + + + +
void DWC_WAITQ_ABORT (dwc_waitq_t *  wq  ) 
+
+
+ +

+Unblock all processes waiting on the waitq with an ABORTED result. +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
dwc_thread_t* DWC_THREAD_RUN (dwc_thread_function_t  thread_function,
char *  name,
void *  data 
)
+
+
+ +

+Create a thread and start it running the thread_function. +

+Returns a handle to the thread +

+

+ +

+
+ + + + + + + + + +
int DWC_THREAD_STOP (dwc_thread_t *  thread  ) 
+
+
+ +

+Stops a thread. +

+Return the value returned by the thread. Or will return DWC_ABORT if the thread never started. +

+

+ +

+
+ + + + + + + + + +
dwc_bool_t DWC_THREAD_SHOULD_STOP (void   ) 
+
+
+ +

+Signifies to the thread that it must stop. +

+ +

+

+ +

+
+ + + + + + + + + +
dwc_workq_t* DWC_WORKQ_ALLOC (char *  name  ) 
+
+
+ +

+Allocate a workq. +

+ +

+

+ +

+
+ + + + + + + + + +
void DWC_WORKQ_FREE (dwc_workq_t *  workq  ) 
+
+
+ +

+Free a workq. +

+All work must be completed before being freed. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void DWC_WORKQ_SCHEDULE (dwc_workq_t *  workq,
dwc_work_callback_t  work_cb,
void *  data,
char *  format,
  ... 
)
+
+
+ +

+Schedule a callback on the workq, passing in data. +

+The function will be scheduled at some later time. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void DWC_WORKQ_SCHEDULE_DELAYED (dwc_workq_t *  workq,
dwc_work_callback_t  work_cb,
void *  data,
uint32_t  time,
char *  format,
  ... 
)
+
+
+ +

+Schedule a callback on the workq, that will be called until at least given number miliseconds have passed. +

+ +

+

+ +

+
+ + + + + + + + + +
int DWC_WORKQ_PENDING (dwc_workq_t *  workq  ) 
+
+
+ +

+The number of processes in the workq. +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int DWC_WORKQ_WAIT_WORK_DONE (dwc_workq_t *  workq,
int  timeout 
)
+
+
+ +

+Blocks until all the work in the workq is complete or timed out. +

+Returns < 0 on timeout. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void DWC_TIMER_SCHEDULE (dwc_timer_t *  timer,
uint32_t  time 
)
+
+
+ +

+Schedules the timer to run at time ms from now. +

+And will repeat at every repeat_interval msec therafter

+Modifies a timer that is still awaiting execution to a new expiration time. The mod_time is added to the old time. +

+

+ +

+
+ + + + + + + + + +
void DWC_TIMER_CANCEL (dwc_timer_t *  timer  ) 
+
+
+ +

+Disables the timer from execution. +

+ +

+

+ +

+
+ + + + + + + + + +
dwc_spinlock_t* DWC_SPINLOCK_ALLOC (void   ) 
+
+
+ +

+Returns an initialized lock variable. +

+This function should allocate and initialize the OS-specific data structure used for locking. This data structure is to be used for the DWC_LOCK and DWC_UNLOCK functions and should be freed by the DWC_FREE_LOCK when it is no longer used. +

+

+ +

+
+ + + + + + + + + +
void DWC_SPINLOCK_FREE (dwc_spinlock_t *  lock  ) 
+
+
+ +

+Frees an initialized lock variable. +

+ +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void DWC_SPINLOCK_IRQSAVE (dwc_spinlock_t *  lock,
uint64_t *  flags 
)
+
+
+ +

+Disables interrupts and blocks until it acquires the lock. +

+

Parameters:
+ + + +
lock Pointer to the spinlock.
flags Unsigned long for irq flags storage.
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void DWC_SPINUNLOCK_IRQRESTORE (dwc_spinlock_t *  lock,
uint64_t  flags 
)
+
+
+ +

+Re-enables the interrupt and releases the lock. +

+

Parameters:
+ + + +
lock Pointer to the spinlock.
flags Unsigned long for irq flags storage. Must be the same as was passed into DWC_LOCK.
+
+ +
+

+ +

+
+ + + + + + + + + +
void DWC_SPINLOCK (dwc_spinlock_t *  lock  ) 
+
+
+ +

+Blocks until it acquires the lock. +

+

Parameters:
+ + +
lock Pointer to the spinlock.
+
+ +
+

+ +

+
+ + + + + + + + + +
void DWC_SPINUNLOCK (dwc_spinlock_t *  lock  ) 
+
+
+ +

+Releases the lock. +

+

Parameters:
+ + +
lock Pointer to the spinlock.
+
+ +
+

+ +

+
+ + + + + + + + + +
int DWC_MUTEX_TRYLOCK (dwc_mutex_t *  mutex  ) 
+
+
+ +

+Non-blocking lock returns 1 on successful lock. +

+ +

+

+ +

+
+ + + + + + + + + +
void DWC_UDELAY (uint32_t  usecs  ) 
+
+
+ +

+Microsecond delay. +

+

Parameters:
+ + +
usecs Microseconds to delay.
+
+ +
+

+ +

+
+ + + + + + + + + +
void DWC_MDELAY (uint32_t  msecs  ) 
+
+
+ +

+Millisecond delay. +

+

Parameters:
+ + +
msecs Milliseconds to delay.
+
+ +
+

+ +

+
+ + + + + + + + + +
void DWC_MSLEEP (uint32_t  msecs  ) 
+
+
+ +

+Non-busy waiting. +

+Sleeps for specified number of milliseconds.

+

Parameters:
+ + +
msecs Milliseconds to sleep.
+
+ +
+

+


Generated on Tue May 5 02:22:50 2009 for Synopsys DWC Portability and Common Library for UWB by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_common_port/doc/html/files.html b/drivers/usb/host/dwc_common_port/doc/html/files.html new file mode 100644 index 000000000000..da3c83bf1a05 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/files.html @@ -0,0 +1,34 @@ + + +Synopsys DWC Portability and Common Library for UWB: File Index + + + + + + +

Synopsys DWC Portability and Common Library for UWB File List

Here is a list of all documented files with brief descriptions: + + + + + + + + +
dwc_cc.hThis file defines the Context Context library
dwc_crypto.cThis file contains the WUSB cryptographic routines
dwc_crypto.hThis file contains declarations for the WUSB Cryptographic routines as defined in the WUSB spec
dwc_dh.hThis file defines the common functions on device and host for performing numeric association as defined in the WUSB spec
dwc_list.hThis file defines linked list operations
dwc_modpow.hThis file defines the module exponentiation function which is only used internally by the DWC UWB modules for calculation of PKs during numeric association
dwc_notifier.hA simple implementation of the Observer pattern
dwc_os.hDWC portability library, low level os-wrapper functions
+
Generated on Tue May 5 02:22:50 2009 for Synopsys DWC Portability and Common Library for UWB by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_common_port/doc/html/globals.html b/drivers/usb/host/dwc_common_port/doc/html/globals.html new file mode 100644 index 000000000000..1149474d792f --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/globals.html @@ -0,0 +1,163 @@ + + +Synopsys DWC Portability and Common Library for UWB: Data Fields + + + + + + +
+ +
+
+
    +
  • _
  • +
  • d
  • +
+
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- _ -

+

- d -

+
Generated on Tue May 5 02:22:50 2009 for Synopsys DWC Portability and Common Library for UWB by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_common_port/doc/html/globals_defs.html b/drivers/usb/host/dwc_common_port/doc/html/globals_defs.html new file mode 100644 index 000000000000..c7dea18895fd --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/globals_defs.html @@ -0,0 +1,41 @@ + + +Synopsys DWC Portability and Common Library for UWB: Data Fields + + + + + + +
+ +
+  +

+

+
Generated on Tue May 5 02:22:50 2009 for Synopsys DWC Portability and Common Library for UWB by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_common_port/doc/html/globals_func.html b/drivers/usb/host/dwc_common_port/doc/html/globals_func.html new file mode 100644 index 000000000000..ee875e83a22b --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/globals_func.html @@ -0,0 +1,153 @@ + + +Synopsys DWC Portability and Common Library for UWB: Data Fields + + + + + + +
+ +
+
+
    +
  • _
  • +
  • d
  • +
+
+ +

+  +

+

- _ -

+

- d -

+
Generated on Tue May 5 02:22:50 2009 for Synopsys DWC Portability and Common Library for UWB by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_common_port/doc/html/globals_type.html b/drivers/usb/host/dwc_common_port/doc/html/globals_type.html new file mode 100644 index 000000000000..3f2ddc3a6130 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/globals_type.html @@ -0,0 +1,41 @@ + + +Synopsys DWC Portability and Common Library for UWB: Data Fields + + + + + + +
+ +
+  +

+

+
Generated on Tue May 5 02:22:50 2009 for Synopsys DWC Portability and Common Library for UWB by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_common_port/doc/html/index.html b/drivers/usb/host/dwc_common_port/doc/html/index.html new file mode 100644 index 000000000000..1ffb33dc8ecf --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/index.html @@ -0,0 +1,8 @@ + + +Synopsys DWC Portability and Common Library for UWB + + + + + diff --git a/drivers/usb/host/dwc_common_port/doc/html/main.html b/drivers/usb/host/dwc_common_port/doc/html/main.html new file mode 100644 index 000000000000..f8ab40c5026f --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/main.html @@ -0,0 +1,45 @@ + + +Synopsys DWC Portability and Common Library for UWB: DWC Portability and Common Library + + + + + +

DWC Portability and Common Library

+

+This is the documentation for the DWC Portability and Common Library.

+Introduction

+The DWC Portability library consists of wrapper calls and data structures to all low-level functions which are typically provided by the OS. The WUDEV driver uses only these functions. In order to port the WUDEV driver, only the functions in this library need to be re-implemented, with the same behavior as documented here.

+The Common library consists of higher level functions, which rely only on calling the functions from the DWC Portability library. These common routines are shared across modules. Some of the common libraries need to be used directly by the driver programmer when porting WUDEV. Such as the parameter and notification libraries.

+Portability Library OS Wrapper Functions

+Any function starting with DWC and in all CAPS is a low-level OS-wrapper that needs to be implemented when porting, for example DWC_MUTEX_ALLOC(). All of these functions are included in the dwc_os.h file.

+There are many functions here covering a wide array of OS services. Please see dwc_os.h for details, and implementation notes for each function.

+Common Library Functions

+Any function starting with dwc and in all lowercase is a common library routine. These functions have a portable implementation and do not need to be reimplemented when porting. The common routines can be used by any driver, and some must be used by the end user to control the drivers. For example, you must use the Parameter common library in order to set the parameters in the WUDEV module.

+The common libraries consist of the following:

+

+

+Prerequistes For dwc_os.h

+

+Data Types

+The dwc_os.h file assumes that several low-level data types are pre defined for the compilation environment. These data types are:

+

+

+Ensure that these are defined before using dwc_os.h. The easiest way to do that is to modify the top of the file to include the appropriate header. This is already done for the Linux environment. If the DWC_LINUX macro is defined, the correct header will be added. A standard header <stdint.h> is also used for environments where standard C headers are available.

+Variable Arguments

+Variable arguments are provided by a standard C header <stdarg.h>. it is available in Both the Linux and ANSI C enviornment. An equivalent must be provided in your enviornment in order to use dwc_os.h with the debug and tracing message functionality.

+Threading

+WUDEV Core must be run on an operating system that provides for multiple threads/processes. Threading can be implemented in many ways, even in embedded systems without an operating system. At the bare minimum, the system should be able to start any number of processes at any time to handle special work. It need not be a pre-emptive system. Process context can change upon a call to a blocking function. The hardware interrupt context that calls the module's ISR() function must be differentiable from process context, even if your processes are impemented via a hardware interrupt. Further locking mechanism between process must exist (or be implemented), and process context must have a way to disable interrupts for a period of time to lock them out. If all of this exists, the functions in dwc_os.h related to threading should be able to be implemented with the defined behavior.
Generated on Tue May 5 02:22:50 2009 for Synopsys DWC Portability and Common Library for UWB by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_common_port/doc/html/pages.html b/drivers/usb/host/dwc_common_port/doc/html/pages.html new file mode 100644 index 000000000000..09e4bb0fa605 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/pages.html @@ -0,0 +1,23 @@ + + +Synopsys DWC Portability and Common Library for UWB: Page Index + + + + + +

Synopsys DWC Portability and Common Library for UWB Related Pages

Here is a list of all related documentation pages: +
Generated on Tue May 5 02:22:50 2009 for Synopsys DWC Portability and Common Library for UWB by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_common_port/doc/html/tabs.css b/drivers/usb/host/dwc_common_port/doc/html/tabs.css new file mode 100644 index 000000000000..a61552a67ad2 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/tabs.css @@ -0,0 +1,102 @@ +/* tabs styles, based on http://www.alistapart.com/articles/slidingdoors */ + +DIV.tabs +{ + float : left; + width : 100%; + background : url("tab_b.gif") repeat-x bottom; + margin-bottom : 4px; +} + +DIV.tabs UL +{ + margin : 0px; + padding-left : 10px; + list-style : none; +} + +DIV.tabs LI, DIV.tabs FORM +{ + display : inline; + margin : 0px; + padding : 0px; +} + +DIV.tabs FORM +{ + float : right; +} + +DIV.tabs A +{ + float : left; + background : url("tab_r.gif") no-repeat right top; + border-bottom : 1px solid #84B0C7; + font-size : x-small; + font-weight : bold; + text-decoration : none; +} + +DIV.tabs A:hover +{ + background-position: 100% -150px; +} + +DIV.tabs A:link, DIV.tabs A:visited, +DIV.tabs A:active, DIV.tabs A:hover +{ + color: #1A419D; +} + +DIV.tabs SPAN +{ + float : left; + display : block; + background : url("tab_l.gif") no-repeat left top; + padding : 5px 9px; + white-space : nowrap; +} + +DIV.tabs INPUT +{ + float : right; + display : inline; + font-size : 1em; +} + +DIV.tabs TD +{ + font-size : x-small; + font-weight : bold; + text-decoration : none; +} + + + +/* Commented Backslash Hack hides rule from IE5-Mac \*/ +DIV.tabs SPAN {float : none;} +/* End IE5-Mac hack */ + +DIV.tabs A:hover SPAN +{ + background-position: 0% -150px; +} + +DIV.tabs LI#current A +{ + background-position: 100% -150px; + border-width : 0px; +} + +DIV.tabs LI#current SPAN +{ + background-position: 0% -150px; + padding-bottom : 6px; +} + +DIV.nav +{ + background : none; + border : none; + border-bottom : 1px solid #84B0C7; +} diff --git a/drivers/usb/host/dwc_common_port/doc/html/todo.html b/drivers/usb/host/dwc_common_port/doc/html/todo.html new file mode 100644 index 000000000000..c976dc2505d3 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/todo.html @@ -0,0 +1,23 @@ + + +Synopsys DWC Portability and Common Library for UWB: Todo List + + + + + +

Todo List

+
Global __DWC_DMA_ALLOC
+
these functions will be added in the future
+
+
Generated on Tue May 5 02:22:50 2009 for Synopsys DWC Portability and Common Library for UWB by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_common_port/doc/html/tree.html b/drivers/usb/host/dwc_common_port/doc/html/tree.html new file mode 100644 index 000000000000..ec0914f7bddf --- /dev/null +++ b/drivers/usb/host/dwc_common_port/doc/html/tree.html @@ -0,0 +1,90 @@ + + + + + + + TreeView + + + + + + + diff --git a/drivers/usb/host/dwc_common_port/dwc_cc.c b/drivers/usb/host/dwc_common_port/dwc_cc.c new file mode 100644 index 000000000000..3a7dd711ce60 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/dwc_cc.c @@ -0,0 +1,506 @@ +/* ========================================================================= + * $File: //dwh/usb_iip/dev/software/dwc_common_port/dwc_cc.c $ + * $Revision: #1 $ + * $Date: 2008/12/21 $ + * $Change: 1156609 $ + * + * Synopsys Portability Library Software and documentation + * (hereinafter, "Software") is an Unsupported proprietary work of + * Synopsys, Inc. unless otherwise expressly agreed to in writing + * between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product + * under any End User Software License Agreement or Agreement for + * Licensed Product with Synopsys or any supplement thereto. You are + * permitted to use and redistribute this Software in source and binary + * forms, with or without modification, provided that redistributions + * of source code must retain this notice. You may not view, use, + * disclose, copy or distribute this file or any information contained + * herein except pursuant to this license grant from Synopsys. If you + * do not agree with this notice, including the disclaimer below, then + * you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================= */ +#include "dwc_cc.h" + +typedef struct dwc_cc +{ + uint32_t uid; + uint8_t chid[16]; + uint8_t cdid[16]; + uint8_t ck[16]; + uint8_t *name; + uint8_t length; + DWC_CIRCLEQ_ENTRY(dwc_cc) list_entry; +} dwc_cc_t; + +DWC_CIRCLEQ_HEAD(context_list, dwc_cc); + +/** The main structure for CC management. */ +struct dwc_cc_if +{ + dwc_mutex_t *mutex; + char *filename; + + unsigned is_host:1; + + dwc_notifier_t *notifier; + + struct context_list list; +}; + +#ifdef DEBUG +static inline void dump_bytes(char *name, uint8_t *bytes, int len) +{ + int i; + DWC_PRINTF("%s: ", name); + for (i=0; ilength = length; + cc->name = DWC_ALLOC(length); + DWC_MEMCPY(cc->name, name, length); + } + + return cc; +} + +static void free_cc(dwc_cc_t *cc) +{ + if (cc->name) { + DWC_FREE(cc->name); + } + DWC_FREE(cc); +} + +static uint32_t next_uid(dwc_cc_if_t *cc_if) +{ + uint32_t uid = 0; + dwc_cc_t *cc; + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) { + if (cc->uid > uid) { + uid = cc->uid; + } + } + + if (uid == 0) { + uid = 255; + } + + return uid + 1; +} + +static dwc_cc_t *cc_find(dwc_cc_if_t *cc_if, uint32_t uid) +{ + dwc_cc_t *cc; + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) { + if (cc->uid == uid) { + return cc; + } + } + return NULL; +} + +static unsigned int cc_data_size(dwc_cc_if_t *cc_if) +{ + unsigned int size = 0; + dwc_cc_t *cc; + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) { + size += (48 + 1); + if (cc->name) { + size += cc->length; + } + } + return size; +} + +static uint32_t cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid) +{ + uint32_t uid = 0; + dwc_cc_t *cc; + + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) { + if (DWC_MEMCMP(cc->chid, chid, 16) == 0) { + uid = cc->uid; + break; + } + } + return uid; +} +static uint32_t cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid) +{ + uint32_t uid = 0; + dwc_cc_t *cc; + + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) { + if (DWC_MEMCMP(cc->cdid, cdid, 16) == 0) { + uid = cc->uid; + break; + } + } + return uid; +} + +/* Internal cc_add */ +static int32_t cc_add(dwc_cc_if_t *cc_if, uint8_t *chid, uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length) +{ + dwc_cc_t *cc; + uint32_t uid; + + if (cc_if->is_host) { + uid = cc_match_cdid(cc_if, cdid); + } + else { + uid = cc_match_chid(cc_if, chid); + } + + if (uid) { + DWC_DEBUG("Replacing previous connection context id=%d name=%p name_len=%d", uid, name, length); + cc = cc_find(cc_if, uid); + } + else { + cc = alloc_cc(name, length); + cc->uid = next_uid(cc_if); + DWC_CIRCLEQ_INSERT_TAIL(&cc_if->list, cc, list_entry); + } + + DWC_MEMCPY(&(cc->chid[0]), chid, 16); + DWC_MEMCPY(&(cc->cdid[0]), cdid, 16); + DWC_MEMCPY(&(cc->ck[0]), ck, 16); + + DWC_DEBUG("Added connection context id=%d name=%p name_len=%d", cc->uid, name, length); + dump_bytes("CHID", cc->chid, 16); + dump_bytes("CDID", cc->cdid, 16); + dump_bytes("CK", cc->ck, 16); + return cc->uid; +} + +/* Internal cc_clear */ +static void cc_clear(dwc_cc_if_t *cc_if) +{ + while (!DWC_CIRCLEQ_EMPTY(&cc_if->list)) { + dwc_cc_t *cc = DWC_CIRCLEQ_FIRST(&cc_if->list); + DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry); + free_cc(cc); + } +} + +dwc_cc_if_t *dwc_cc_if_alloc(dwc_notifier_t *notifier, unsigned is_host) +{ + dwc_cc_if_t *cc_if = NULL; + + /* Allocate a common_cc_if structure */ + cc_if = DWC_ALLOC(sizeof(dwc_cc_if_t)); + + if(!cc_if) + return NULL; + +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)) + DWC_MUTEX_ALLOC_LINUX_DEBUG(cc_if->mutex); +#else + cc_if->mutex = DWC_MUTEX_ALLOC(); +#endif + DWC_CIRCLEQ_INIT(&cc_if->list); + cc_if->is_host = is_host; + cc_if->notifier = notifier; + return cc_if; +} + +void dwc_cc_if_free(dwc_cc_if_t *cc_if) +{ + DWC_MUTEX_FREE(cc_if->mutex); + cc_clear(cc_if); + DWC_FREE(cc_if); +} + +static void cc_changed(dwc_cc_if_t *cc_if) +{ + if (cc_if->notifier) { + dwc_notify(cc_if->notifier, DWC_CC_LIST_CHANGED_NOTIFICATION, cc_if); + } +} + +void dwc_cc_clear(dwc_cc_if_t *cc_if) +{ + DWC_MUTEX_LOCK(cc_if->mutex); + cc_clear(cc_if); + DWC_MUTEX_UNLOCK(cc_if->mutex); + cc_changed(cc_if); +} + +int32_t dwc_cc_add(dwc_cc_if_t *cc_if, uint8_t *chid, uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length) +{ + uint32_t uid; + + DWC_MUTEX_LOCK(cc_if->mutex); + uid = cc_add(cc_if, chid, cdid, ck, name, length); + DWC_MUTEX_UNLOCK(cc_if->mutex); + cc_changed(cc_if); + + return uid; +} + +void dwc_cc_change(dwc_cc_if_t *cc_if, int32_t id, + uint8_t *chid, uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length) +{ + dwc_cc_t* cc; + + DWC_DEBUG("Change connection context %d", id); + + DWC_MUTEX_LOCK(cc_if->mutex); + cc = cc_find(cc_if, id); + if (!cc) { + DWC_ERROR("Uid %d not found in cc list", id); + DWC_MUTEX_UNLOCK(cc_if->mutex); + return; + } + + if (chid) { + DWC_MEMCPY(&(cc->chid[0]), chid, 16); + } + if (cdid) { + DWC_MEMCPY(&(cc->cdid[0]), cdid, 16); + } + if (ck) { + DWC_MEMCPY(&(cc->ck[0]), ck, 16); + } + + if (name) { + if (cc->name) { + DWC_FREE(cc->name); + } + cc->name = DWC_ALLOC(length); + cc->length = length; + DWC_MEMCPY(cc->name, name, length); + } + + DWC_MUTEX_UNLOCK(cc_if->mutex); + + cc_changed(cc_if); + + DWC_DEBUG("Changed connection context id=%d\n", id); + dump_bytes("New CHID", cc->chid, 16); + dump_bytes("New CDID", cc->cdid, 16); + dump_bytes("New CK", cc->ck, 16); +} + +void dwc_cc_remove(dwc_cc_if_t *cc_if, int32_t id) +{ + dwc_cc_t *cc; + + DWC_DEBUG("Removing connection context %d", id); + + DWC_MUTEX_LOCK(cc_if->mutex); + cc = cc_find(cc_if, id); + if (!cc) { + DWC_ERROR("Uid %d not found in cc list", id); + DWC_MUTEX_UNLOCK(cc_if->mutex); + return; + } + + DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry); + DWC_MUTEX_UNLOCK(cc_if->mutex); + free_cc(cc); + + cc_changed(cc_if); +} + +uint8_t *dwc_cc_data_for_save(dwc_cc_if_t *cc_if, unsigned int *length) +{ + uint8_t *buf, *x; + uint8_t zero = 0; + dwc_cc_t *cc; + + DWC_MUTEX_LOCK(cc_if->mutex); + *length = cc_data_size(cc_if); + if (!(*length)) { + DWC_MUTEX_UNLOCK(cc_if->mutex); + return NULL; + } + + DWC_DEBUG("Creating data for saving (length=%d)", *length); + + buf = DWC_ALLOC(*length); + if (!buf) { + *length = 0; + DWC_MUTEX_UNLOCK(cc_if->mutex); + return NULL; + } + + x = buf; + DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) { + DWC_MEMCPY(x, cc->chid, 16); + x += 16; + DWC_MEMCPY(x, cc->cdid, 16); + x += 16; + DWC_MEMCPY(x, cc->ck, 16); + x += 16; + if (cc->name) { + DWC_MEMCPY(x, &cc->length, 1); + x += 1; + DWC_MEMCPY(x, cc->name, cc->length); + x += cc->length; + } + else { + DWC_MEMCPY(x, &zero, 1); + x += 1; + } + } + DWC_MUTEX_UNLOCK(cc_if->mutex); + + return buf; +} + +void dwc_cc_restore_from_data(dwc_cc_if_t *cc_if, uint8_t *data, uint32_t length) +{ + uint8_t name_length; + uint8_t *name; + uint8_t *chid; + uint8_t *cdid; + uint8_t *ck; + uint32_t i = 0; + + DWC_MUTEX_LOCK(cc_if->mutex); + cc_clear(cc_if); + + while (i < length) { + chid = &data[i]; + i += 16; + cdid = &data[i]; + i += 16; + ck = &data[i]; + i += 16; + + name_length = data[i]; + i ++; + + if (name_length) { + name = &data[i]; + i += name_length; + } + else { + name = NULL; + } + + /* check to see if we haven't overflown the buffer */ + if (i > length) { + DWC_ERROR("Data format error while attempting to load CCs " + "(nlen=%d, iter=%d, buflen=%d).", name_length, i, length); + break; + } + + cc_add(cc_if, chid, cdid, ck, name, name_length); + } + DWC_MUTEX_UNLOCK(cc_if->mutex); + + cc_changed(cc_if); +} + +uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid) +{ + uint32_t uid = 0; + + DWC_MUTEX_LOCK(cc_if->mutex); + uid = cc_match_chid(cc_if, chid); + DWC_MUTEX_UNLOCK(cc_if->mutex); + return uid; +} +uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid) +{ + uint32_t uid = 0; + + DWC_MUTEX_LOCK(cc_if->mutex); + uid = cc_match_cdid(cc_if, cdid); + DWC_MUTEX_UNLOCK(cc_if->mutex); + return uid; +} + +uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id) +{ + uint8_t *ck = NULL; + dwc_cc_t *cc; + + DWC_MUTEX_LOCK(cc_if->mutex); + cc = cc_find(cc_if, id); + if (cc) { + ck = cc->ck; + } + DWC_MUTEX_UNLOCK(cc_if->mutex); + + return ck; + +} + +uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id) +{ + uint8_t *retval = NULL; + dwc_cc_t *cc; + + DWC_MUTEX_LOCK(cc_if->mutex); + cc = cc_find(cc_if, id); + if (cc) { + retval = cc->chid; + } + DWC_MUTEX_UNLOCK(cc_if->mutex); + + return retval; +} + +uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id) +{ + uint8_t *retval = NULL; + dwc_cc_t *cc; + + DWC_MUTEX_LOCK(cc_if->mutex); + cc = cc_find(cc_if, id); + if (cc) { + retval = cc->cdid; + } + DWC_MUTEX_UNLOCK(cc_if->mutex); + + return retval; +} + +uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length) +{ + uint8_t *retval = NULL; + dwc_cc_t *cc; + + DWC_MUTEX_LOCK(cc_if->mutex); + *length = 0; + cc = cc_find(cc_if, id); + if (cc) { + *length = cc->length; + retval = cc->name; + } + DWC_MUTEX_UNLOCK(cc_if->mutex); + + return retval; +} diff --git a/drivers/usb/host/dwc_common_port/dwc_cc.h b/drivers/usb/host/dwc_common_port/dwc_cc.h new file mode 100644 index 000000000000..6b4641918f62 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/dwc_cc.h @@ -0,0 +1,209 @@ +/* ========================================================================= + * $File: //dwh/usb_iip/dev/software/dwc_common_port/dwc_cc.h $ + * $Revision: #1 $ + * $Date: 2008/12/21 $ + * $Change: 1156609 $ + * + * Synopsys Portability Library Software and documentation + * (hereinafter, "Software") is an Unsupported proprietary work of + * Synopsys, Inc. unless otherwise expressly agreed to in writing + * between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product + * under any End User Software License Agreement or Agreement for + * Licensed Product with Synopsys or any supplement thereto. You are + * permitted to use and redistribute this Software in source and binary + * forms, with or without modification, provided that redistributions + * of source code must retain this notice. You may not view, use, + * disclose, copy or distribute this file or any information contained + * herein except pursuant to this license grant from Synopsys. If you + * do not agree with this notice, including the disclaimer below, then + * you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================= */ +#ifndef _DWC_CC_H_ +#define _DWC_CC_H_ + +/** @file + * + * This file defines the Context Context library. + * + * The main data structure is dwc_cc_if_t which is returned by either the + * dwc_cc_if_alloc function or returned by the module to the user via a provided + * function. The data structure is opaque and should only be manipulated via the + * functions provied in this API. + * + * It manages a list of connection contexts and operations can be performed to + * add, remove, query, search, and change, those contexts. Additionally, + * a dwc_notifier_t object can be requested from the manager so that + * the user can be notified whenever the context list has changed. + */ + +#include "dwc_os.h" +#include "dwc_list.h" +#include "dwc_notifier.h" + + +/* Notifications */ +#define DWC_CC_LIST_CHANGED_NOTIFICATION "DWC_CC_LIST_CHANGED_NOTIFICATION" + +struct dwc_cc_if; +typedef struct dwc_cc_if dwc_cc_if_t; + + +/** @name Connection Context Operations */ +/** @{ */ + +/** This function allocates memory for a dwc_cc_if_t structure, initializes + * fields to default values, and returns a pointer to the structure or NULL on + * error. */ +extern dwc_cc_if_t *dwc_cc_if_alloc(dwc_notifier_t *notifier, unsigned is_host); + +/** Frees the memory for the specified CC structure allocated from + * dwc_cc_if_alloc(). */ +extern void dwc_cc_if_free(dwc_cc_if_t *cc_if); + +/** Removes all contexts from the connection context list */ +extern void dwc_cc_clear(dwc_cc_if_t *cc_if); + +/** Adds a connection context (CHID, CK, CDID, Name) to the connection context list. + * If a CHID already exists, the CK and name are overwritten. Statistics are + * not overwritten. + * + * @param cc_if The cc_if structure. + * @param chid A pointer to the 16-byte CHID. This value will be copied. + * @param ck A pointer to the 16-byte CK. This value will be copied. + * @param cdid A pointer to the 16-byte CDID. This value will be copied. + * @param name An optional host friendly name as defined in the association model + * spec. Must be a UTF16-LE unicode string. Can be NULL to indicated no name. + * @param length The length othe unicode string. + * @return A unique identifier used to refer to this context that is valid for + * as long as this context is still in the list. */ +extern int32_t dwc_cc_add(dwc_cc_if_t *cc_if, uint8_t *chid, uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length); + +/** Changes the CHID, CK, CDID, or Name values of a connection context in the + * list, preserving any accumulated statistics. This would typically be called + * if the host decideds to change the context with a SET_CONNECTION request. + * + * @param cc_if The cc_if structure. + * @param id The identifier of the connection context. + * @param chid A pointer to the 16-byte CHID. This value will be copied. NULL + * indicates no change. + * @param cdid A pointer to the 16-byte CDID. This value will be copied. NULL + * indicates no change. + * @param ck A pointer to the 16-byte CK. This value will be copied. NULL + * indicates no change. + * @param name Host friendly name UTF16-LE. NULL indicates no change. + * @param length Length of name. */ +extern void dwc_cc_change(dwc_cc_if_t *cc_if, int32_t id, uint8_t *chid, uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length); + +/** Remove the specified connection context. + * @param cc_if The cc_if structure. + * @param id The identifier of the connection context to remove. */ +extern void dwc_cc_remove(dwc_cc_if_t *cc_if, int32_t id); + +/** Get a binary block of data for the connection context list and attributes. + * This data can be used by the OS specific driver to save the connection + * context list into non-volatile memory. + * + * @param cc_if The cc_if structure. + * @param length Return the length of the data buffer. + * @return A pointer to the data buffer. The memory for this buffer should be freed with DWC_FREE() after use. */ +extern uint8_t *dwc_cc_data_for_save(dwc_cc_if_t *cc_if, unsigned int *length); + +/** Restore the connection context list from the binary data that was previously + * returned from a call to dwc_cc_data_for_save. This can be used by the OS specific + * driver to load a connection context list from non-volatile memory. + * + * @param cc_if The cc_if structure. + * @param data The data bytes as returned from dwc_cc_data_for_save. + * @param length The length of the data. */ +extern void dwc_cc_restore_from_data(dwc_cc_if_t *cc_if, uint8_t *data, unsigned int length); + +/** Find the connection context from the specified CHID. + * + * @param cc_if The cc_if structure. + * @param chid A pointer to the CHID data. + * @return A non-zero identifier of the connection context if the CHID matches. + * Otherwise returns 0. */ +extern uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid); + +/** Find the connection context from the specified CDID. + * + * @param cc_if The cc_if structure. + * @param cdid A pointer to the CDID data. + * @return A non-zero identifier of the connection context if the CHID matches. + * Otherwise returns 0. */ +extern uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid); + +/** Retrieve the CK from the specified connection context. + * + * @param cc_if The cc_if structure. + * @param id The identifier of the connection context. + * @return A pointer to the CK data. The memory does not need to be freed. */ +extern uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id); + +/** Retrieve the CHID from the specified connection context. + * + * @param cc_if The cc_if structure. + * @param id The identifier of the connection context. + * @return A pointer to the CHID data. The memory does not need to be freed. */ +extern uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id); + +/** Retrieve the CDID from the specified connection context. + * + * @param cc_if The cc_if structure. + * @param id The identifier of the connection context. + * @return A pointer to the CDID data. The memory does not need to be freed. */ +extern uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id); + +extern uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length); + +/** Checks a buffer for non-zero. + * @param id A pointer to a 16 byte buffer. + * @return true if the 16 byte value is non-zero. */ +static inline unsigned dwc_assoc_is_not_zero_id(uint8_t *id) { + int i; + for (i=0; i<16; i++) { + if (id[i]) return 1; + } + return 0; +} + +/** Checks a buffer for zero. + * @param id A pointer to a 16 byte buffer. + * @return true if the 16 byte value is zero. */ +static inline unsigned dwc_assoc_is_zero_id(uint8_t *id) { + return !dwc_assoc_is_not_zero_id(id); +} + +/** Prints an ASCII representation for the 16-byte chid, cdid, or ck, into + * buffer. */ +static inline int dwc_print_id_string(char *buffer, uint8_t *id) { + char *ptr = buffer; + int i; + for (i=0; i<16; i++) { + ptr += DWC_SPRINTF(ptr, "%02x", id[i]); + if (i < 15) { + ptr += DWC_SPRINTF(ptr, " "); + } + } + return ptr - buffer; +} + +/** @} */ + +#endif /* _DWC_CC_H_ */ + diff --git a/drivers/usb/host/dwc_common_port/dwc_common_linux.c b/drivers/usb/host/dwc_common_port/dwc_common_linux.c new file mode 100644 index 000000000000..cef068fb46c3 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/dwc_common_linux.c @@ -0,0 +1,1247 @@ +#include "dwc_cc.h" +#include "dwc_modpow.h" +#include "dwc_dh.h" +#include "dwc_crypto.h" +#include "dwc_notifier.h" + +#include +#include +#include +#include + +MODULE_DESCRIPTION("DWC Common Library - Portable version"); +MODULE_AUTHOR("Synopsys Inc."); +MODULE_LICENSE ("GPL"); + +static int dwc_common_port_init_module(void) +{ + printk( KERN_DEBUG "Module dwc_common_port init\n" ); +#ifdef DEBUG_MEMORY + dwc_memory_debug_start(); +#endif + dwc_alloc_notification_manager(); + return 0; +} + +static void dwc_common_port_exit_module(void) +{ + printk( KERN_DEBUG "Module dwc_common_port exit\n" ); + dwc_free_notification_manager(); +#ifdef DEBUG_MEMORY + dwc_memory_debug_stop(); +#endif +} + +module_init(dwc_common_port_init_module); +module_exit(dwc_common_port_exit_module); + +/* CC */ +EXPORT_SYMBOL(dwc_cc_if_alloc); +EXPORT_SYMBOL(dwc_cc_if_free); +EXPORT_SYMBOL(dwc_cc_clear); +EXPORT_SYMBOL(dwc_cc_add); +EXPORT_SYMBOL(dwc_cc_remove); +EXPORT_SYMBOL(dwc_cc_change); +EXPORT_SYMBOL(dwc_cc_data_for_save); +EXPORT_SYMBOL(dwc_cc_restore_from_data); +EXPORT_SYMBOL(dwc_cc_match_chid); +EXPORT_SYMBOL(dwc_cc_match_cdid); +EXPORT_SYMBOL(dwc_cc_ck); +EXPORT_SYMBOL(dwc_cc_chid); +EXPORT_SYMBOL(dwc_cc_cdid); +EXPORT_SYMBOL(dwc_cc_name); + +#ifndef CONFIG_MACH_IPMATE +/* Modpow */ +EXPORT_SYMBOL(dwc_modpow); +/* DH */ +EXPORT_SYMBOL(dwc_dh_modpow); +EXPORT_SYMBOL(dwc_dh_derive_keys); +EXPORT_SYMBOL(dwc_dh_pk); +#endif /* CONFIG_MACH_IPMATE */ +/* Crypto */ +EXPORT_SYMBOL(dwc_wusb_aes_encrypt); +EXPORT_SYMBOL(dwc_wusb_cmf); +EXPORT_SYMBOL(dwc_wusb_prf); +EXPORT_SYMBOL(dwc_wusb_fill_ccm_nonce); +EXPORT_SYMBOL(dwc_wusb_gen_nonce); +EXPORT_SYMBOL(dwc_wusb_gen_key); +EXPORT_SYMBOL(dwc_wusb_gen_mic); + + +/* Notification */ +EXPORT_SYMBOL(dwc_alloc_notification_manager); +EXPORT_SYMBOL(dwc_free_notification_manager); +EXPORT_SYMBOL(dwc_register_notifier); +EXPORT_SYMBOL(dwc_unregister_notifier); +EXPORT_SYMBOL(dwc_add_observer); +EXPORT_SYMBOL(dwc_remove_observer); +EXPORT_SYMBOL(dwc_notify); + +/* Memory Debugging Routines */ +#ifdef DEBUG_MEMORY +EXPORT_SYMBOL(dwc_alloc_debug); +EXPORT_SYMBOL(dwc_alloc_atomic_debug); +EXPORT_SYMBOL(dwc_free_debug); +EXPORT_SYMBOL(dwc_dma_alloc_debug); +EXPORT_SYMBOL(dwc_dma_alloc_atomic_debug); +EXPORT_SYMBOL(dwc_dma_free_debug); +#endif + +/* OS-Level Implementations */ + +/* This is the Linux kernel implementation of the DWC platform library. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +/* MISC */ + +void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size) +{ + return memset(dest, byte, size); +} +EXPORT_SYMBOL(DWC_MEMSET); + +void *DWC_MEMCPY(void *dest, void const *src, uint32_t size) +{ + return memcpy(dest, src, size); +} +EXPORT_SYMBOL(DWC_MEMCPY); + +void *DWC_MEMMOVE(void *dest, void *src, uint32_t size) +{ + return memmove(dest, src, size); +} +EXPORT_SYMBOL(DWC_MEMMOVE); + +int DWC_MEMCMP(void *m1, void *m2, uint32_t size) +{ + return memcmp(m1, m2, size); +} +EXPORT_SYMBOL(DWC_MEMCMP); + +int DWC_STRNCMP(void *s1, void *s2, uint32_t size) +{ + return strncmp(s1, s2, size); +} +EXPORT_SYMBOL(DWC_STRNCMP); + +int DWC_STRCMP(void *s1, void *s2) +{ + return strcmp(s1, s2); +} +EXPORT_SYMBOL(DWC_STRCMP); + +int DWC_STRLEN(char const *str) +{ + return strlen(str); +} +EXPORT_SYMBOL(DWC_STRLEN); + +char *DWC_STRCPY(char *to, const char *from) +{ + return strcpy(to, from); +} +EXPORT_SYMBOL(DWC_STRCPY); + +char *DWC_STRDUP(char const *str) +{ + int len = DWC_STRLEN(str) + 1; + char *new = DWC_ALLOC_ATOMIC(len); + if (!new) { + return NULL; + } + DWC_MEMCPY(new, str, len); + return new; +} +EXPORT_SYMBOL(DWC_STRDUP); + +int DWC_ATOI(char *str, int32_t *value) +{ + char *end = NULL; + *value = simple_strtol(str, &end, 0); + if (*end == '\0') { + return 0; + } + return -1; +} +EXPORT_SYMBOL(DWC_ATOI); + +int DWC_ATOUI(char *str, uint32_t *value) +{ + char *end = NULL; + *value = simple_strtoul(str, &end, 0); + if (*end == '\0') { + return 0; + } + return -1; +} +EXPORT_SYMBOL(DWC_ATOUI); + + +/* From usbstring.c */ +int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len) +{ + int count = 0; + u8 c; + u16 uchar; + + /* this insists on correct encodings, though not minimal ones. + * BUT it currently rejects legit 4-byte UTF-8 code points, + * which need surrogate pairs. (Unicode 3.1 can use them.) + */ + while (len != 0 && (c = (u8) *s++) != 0) { + if (unlikely(c & 0x80)) { + // 2-byte sequence: + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx + if ((c & 0xe0) == 0xc0) { + uchar = (c & 0x1f) << 6; + + c = (u8) *s++; + if ((c & 0xc0) != 0xc0) + goto fail; + c &= 0x3f; + uchar |= c; + + // 3-byte sequence (most CJKV characters): + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx + } else if ((c & 0xf0) == 0xe0) { + uchar = (c & 0x0f) << 12; + + c = (u8) *s++; + if ((c & 0xc0) != 0xc0) + goto fail; + c &= 0x3f; + uchar |= c << 6; + + c = (u8) *s++; + if ((c & 0xc0) != 0xc0) + goto fail; + c &= 0x3f; + uchar |= c; + + /* no bogus surrogates */ + if (0xd800 <= uchar && uchar <= 0xdfff) + goto fail; + + // 4-byte sequence (surrogate pairs, currently rare): + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx + // (uuuuu = wwww + 1) + // FIXME accept the surrogate code points (only) + + } else + goto fail; + } else + uchar = c; + put_unaligned (cpu_to_le16 (uchar), cp++); + count++; + len--; + } + return count; +fail: + return -1; +} +EXPORT_SYMBOL(DWC_UTF8_TO_UTF16LE); + +/* dwc_debug.h */ + +dwc_bool_t DWC_IN_IRQ(void) +{ + return in_irq(); +} +EXPORT_SYMBOL(DWC_IN_IRQ); + +int DWC_IN_BH(void) +{ + return in_softirq(); +} +EXPORT_SYMBOL(DWC_IN_BH); + +void DWC_VPRINTF(char *format, va_list args) +{ + vprintk(format, args); +} +EXPORT_SYMBOL(DWC_VPRINTF); + +int DWC_VSNPRINTF(char *str, int size, char *format, va_list args) +{ + return vsnprintf(str, size, format, args); +} + +void DWC_PRINTF(char *format, ...) +{ + va_list args; + va_start(args, format); + DWC_VPRINTF(format, args); + va_end(args); +} +EXPORT_SYMBOL(DWC_PRINTF); + +int DWC_SPRINTF(char *buffer, char *format, ...) +{ + int retval; + va_list args; + va_start(args, format); + retval = vsprintf(buffer, format, args); + va_end(args); + return retval; +} +EXPORT_SYMBOL(DWC_SPRINTF); + +int DWC_SNPRINTF(char *buffer, int size, char *format, ...) +{ + int retval; + va_list args; + va_start(args, format); + retval = vsnprintf(buffer, size, format, args); + va_end(args); + return retval; +} +EXPORT_SYMBOL(DWC_SNPRINTF); + +void __DWC_WARN(char *format, ...) +{ + va_list args; + va_start(args, format); + DWC_PRINTF(KERN_WARNING); + DWC_VPRINTF(format, args); + va_end(args); +} +EXPORT_SYMBOL(__DWC_WARN); + +void __DWC_ERROR(char *format, ...) +{ + va_list args; + va_start(args, format); + DWC_PRINTF(KERN_ERR); + DWC_VPRINTF(format, args); + va_end(args); +} +EXPORT_SYMBOL(__DWC_ERROR); + +void DWC_EXCEPTION(char *format, ...) +{ + va_list args; + va_start(args, format); + DWC_PRINTF(KERN_ERR); + DWC_VPRINTF(format, args); + va_end(args); + BUG_ON(1); +} +EXPORT_SYMBOL(DWC_EXCEPTION); + +#ifdef DEBUG +void __DWC_DEBUG(char *format, ...) +{ + va_list args; + va_start(args, format); + DWC_PRINTF(KERN_DEBUG); + DWC_VPRINTF(format, args); + va_end(args); +} +EXPORT_SYMBOL(__DWC_DEBUG); +#endif + + + +/* dwc_mem.h */ + +#if 0 +dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size, + uint32_t align, + uint32_t alloc) +{ + struct dma_pool *pool = dma_pool_create("Pool", NULL, + size, align, alloc); + return (dwc_pool_t *)pool; +} + +void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool) +{ + dma_pool_destroy((struct dma_pool *)pool); +} + +void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, U64 *dma_addr) +{ + return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr); +} + +void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, U64 *dma_addr) +{ + void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr); + memset(); +} + +void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr) +{ + dma_pool_free(pool, vaddr, daddr); +} + +#endif + +void *__DWC_DMA_ALLOC(uint32_t size, dwc_dma_t *dma_addr) +{ + void *buf = dma_alloc_coherent(NULL, (size_t)size, dma_addr, GFP_KERNEL); + if (!buf) { + return NULL; + } + memset(buf, 0, (size_t)size); + return buf; +} +EXPORT_SYMBOL(__DWC_DMA_ALLOC); + +void __DWC_DMA_FREE(uint32_t size, void *virt_addr, dwc_dma_t dma_addr) +{ + dma_free_coherent(NULL, size, virt_addr, dma_addr); +} +EXPORT_SYMBOL(__DWC_DMA_FREE); + +void *__DWC_DMA_ALLOC_ATOMIC(uint32_t size, dwc_dma_t *dma_addr) +{ + void *buf = dma_alloc_coherent(NULL, (size_t)size, dma_addr, GFP_ATOMIC); + if (!buf) { + return NULL; + } + memset(buf, 0, (size_t)size); + return buf; +} +EXPORT_SYMBOL(__DWC_DMA_ALLOC_ATOMIC); + +void *__DWC_ALLOC(uint32_t size) +{ + return kzalloc(size, GFP_KERNEL); +} +EXPORT_SYMBOL(__DWC_ALLOC); + +void *__DWC_ALLOC_ATOMIC(uint32_t size) +{ + return kzalloc(size, GFP_ATOMIC); +} +EXPORT_SYMBOL(__DWC_ALLOC_ATOMIC); + +void __DWC_FREE(void *addr) +{ + kfree(addr); +} +EXPORT_SYMBOL(__DWC_FREE); + +/* dwc_crypto.h */ + +void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length) +{ + get_random_bytes(buffer, length); +} +EXPORT_SYMBOL(DWC_RANDOM_BYTES); + +int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out) +{ + struct crypto_blkcipher *tfm; + struct blkcipher_desc desc; + struct scatterlist sgd; + struct scatterlist sgs; + + tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC); + if (tfm == NULL) { + printk("failed to load transform for aes CBC\n"); + return -1; + } + + crypto_blkcipher_setkey(tfm, key, keylen); + crypto_blkcipher_set_iv(tfm, iv, 16); + + sg_init_one(&sgd, out, messagelen); + sg_init_one(&sgs, message, messagelen); + + desc.tfm = tfm; + desc.flags = 0; + + if(crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) { + crypto_free_blkcipher(tfm); + DWC_ERROR("AES CBC encryption failed"); + return -1; + } + + crypto_free_blkcipher(tfm); + return 0; +} +EXPORT_SYMBOL(DWC_AES_CBC); + +int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out) +{ + struct crypto_hash *tfm; + struct hash_desc desc; + struct scatterlist sg; + + tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) { + DWC_ERROR("Failed to load transform for sha256: %ld\n", PTR_ERR(tfm)); + return 0; + } + desc.tfm = tfm; + desc.flags = 0; + + sg_init_one(&sg, message, len); + crypto_hash_digest(&desc, &sg, len, out); + crypto_free_hash(tfm); + + return 1; +} +EXPORT_SYMBOL(DWC_SHA256); + +int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen, + uint8_t *key, uint32_t keylen, uint8_t *out) +{ + struct crypto_hash *tfm; + struct hash_desc desc; + struct scatterlist sg; + + tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) { + DWC_ERROR("Failed to load transform for hmac(sha256): %ld\n", PTR_ERR(tfm)); + return 0; + } + desc.tfm = tfm; + desc.flags = 0; + + sg_init_one(&sg, message, messagelen); + crypto_hash_setkey(tfm, key, keylen); + crypto_hash_digest(&desc, &sg, messagelen, out); + crypto_free_hash(tfm); + + return 1; +} +EXPORT_SYMBOL(DWC_HMAC_SHA256); + +/* Byte Ordering Conversions. */ +uint32_t DWC_CPU_TO_LE32(void *p) +{ +#ifdef __LITTLE_ENDIAN + return *((uint32_t *)p); +#else + uint8_t *u_p = (uint8_t *)p; + + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24)); +#endif +} +EXPORT_SYMBOL(DWC_CPU_TO_LE32); + +uint32_t DWC_CPU_TO_BE32(void *p) +{ +#ifdef __BIG_ENDIAN + return *((uint32_t *)p); +#else + uint8_t *u_p = (uint8_t *)p; + + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24)); +#endif +} +EXPORT_SYMBOL(DWC_CPU_TO_BE32); + +uint32_t DWC_LE32_TO_CPU(void *p) +{ +#ifdef __LITTLE_ENDIAN + return *((uint32_t *)p); +#else + uint8_t *u_p = (uint8_t *)p; + + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24)); + +#endif +} +EXPORT_SYMBOL(DWC_LE32_TO_CPU); + +uint32_t DWC_BE32_TO_CPU(void *p) +{ +#ifdef __BIG_ENDIAN + return *((uint32_t *)p); +#else + uint8_t *u_p = (uint8_t *)p; + + return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24)); +#endif +} +EXPORT_SYMBOL(DWC_BE32_TO_CPU); + +uint16_t DWC_CPU_TO_LE16(void *p) +{ +#ifdef __LITTLE_ENDIAN + return *((uint16_t *)p); +#else + uint8_t *u_p = (uint8_t *)p; + return (u_p[1] | (u_p[0] << 8)); +#endif +} +EXPORT_SYMBOL(DWC_CPU_TO_LE16); + +uint16_t DWC_CPU_TO_BE16(void *p) +{ +#ifdef __BIG_ENDIAN + return *((uint16_t *)p); +#else + uint8_t *u_p = (uint8_t *)p; + return (u_p[1] | (u_p[0] << 8)); +#endif +} +EXPORT_SYMBOL(DWC_CPU_TO_BE16); + +uint16_t DWC_LE16_TO_CPU(void *p) +{ +#ifdef __LITTLE_ENDIAN + return *((uint16_t *)p); +#else + uint8_t *u_p = (uint8_t *)p; + return (u_p[1] | (u_p[0] << 8)); +#endif +} +EXPORT_SYMBOL(DWC_LE16_TO_CPU); + +uint16_t DWC_BE16_TO_CPU(void *p) +{ +#ifdef __BIG_ENDIAN + return *((uint16_t *p)p); +#else + uint8_t *u_p = (uint8_t *)p; + return (u_p[1] | (u_p[0] << 8)); +#endif +} +EXPORT_SYMBOL(DWC_BE16_TO_CPU); + + +/* Registers */ + +uint32_t DWC_READ_REG32(uint32_t volatile *reg) +{ + return readl(reg); +} +EXPORT_SYMBOL(DWC_READ_REG32); + +#if 0 +uint64_t DWC_READ_REG64(uint64_t volatile *reg) +{ +} +#endif + +void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value) +{ + writel(value, reg); +} +EXPORT_SYMBOL(DWC_WRITE_REG32); + +#if 0 +void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value) +{ +} +#endif + +void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask) +{ + writel( (readl(reg) & ~clear_mask) | set_mask, reg ); +} +EXPORT_SYMBOL(DWC_MODIFY_REG32); + +#if 0 +void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t value) +{ +} +#endif + + + +/* Threading */ + +typedef struct work_container +{ + dwc_work_callback_t cb; + void *data; + dwc_workq_t *wq; + char *name; + +#ifdef DEBUG + DWC_CIRCLEQ_ENTRY(work_container) entry; +#endif + + struct delayed_work work; +} work_container_t; + +#ifdef DEBUG +DWC_CIRCLEQ_HEAD(work_container_queue, work_container); +#endif + +struct dwc_workq +{ + struct workqueue_struct *wq; + int pending; + dwc_spinlock_t *lock; + dwc_waitq_t *waitq; + +#ifdef DEBUG + struct work_container_queue entries; +#endif +}; + +static void do_work(struct work_struct *work) +{ + int64_t flags; + struct delayed_work *dw = container_of(work, struct delayed_work, work); + work_container_t *container = container_of(dw, struct work_container, work); + dwc_workq_t *wq = container->wq; + + container->cb(container->data); + +#ifdef DEBUG + DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry); +#endif + + if (container->name) { + DWC_DEBUG("Work done: %s, container=%p", + container->name, container); //GRAYG + DWC_FREE(container->name); + } + DWC_FREE(container); + + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags); + wq->pending --; + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags); + DWC_WAITQ_TRIGGER(wq->waitq); +} + +static int work_done(void *data) +{ + dwc_workq_t *workq = (dwc_workq_t *)data; + return workq->pending == 0; +} + +int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout) +{ + return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout); +} +EXPORT_SYMBOL(DWC_WORKQ_WAIT_WORK_DONE); + +dwc_workq_t *DWC_WORKQ_ALLOC(char *name) +{ + dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq)); + wq->wq = create_singlethread_workqueue(name); + wq->pending = 0; + wq->lock = DWC_SPINLOCK_ALLOC(); + wq->waitq = DWC_WAITQ_ALLOC(); +#ifdef DEBUG + DWC_CIRCLEQ_INIT(&wq->entries); +#endif + return wq; +} +EXPORT_SYMBOL(DWC_WORKQ_ALLOC); + +void DWC_WORKQ_FREE(dwc_workq_t *wq) +{ +#ifdef DEBUG + if (wq->pending != 0) { + struct work_container *wc; + DWC_ERROR("Destroying work queue with pending work"); + DWC_CIRCLEQ_FOREACH(wc, &wq->entries, entry) { + DWC_ERROR("Work %s still pending", wc->name); + } + } +#endif + destroy_workqueue((struct workqueue_struct *)wq->wq); + DWC_SPINLOCK_FREE(wq->lock); + DWC_WAITQ_FREE(wq->waitq); + DWC_FREE(wq); +} +EXPORT_SYMBOL(DWC_WORKQ_FREE); + +void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t work_cb, void *data, char *format, ...) +{ + int64_t flags; + work_container_t *container; + static char name[128]; + + va_list args; + va_start(args, format); + if (format) + DWC_VSNPRINTF(name, 128, format, args); + va_end(args); + + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags); + wq->pending ++; + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags); + DWC_WAITQ_TRIGGER(wq->waitq); + + container = DWC_ALLOC_ATOMIC(sizeof(*container)); + + container->data = data; + container->cb = work_cb; + container->wq = wq; + if (format) { + container->name = DWC_STRDUP(name); + DWC_DEBUG("Queueing work: %s, contianer=%p", + container->name, container); + } else + container->name = NULL; + + INIT_WORK(&container->work.work, do_work); + +#ifdef DEBUG + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry); +#endif + + queue_work(wq->wq, &container->work.work); + +} +EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE); + +void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t work_cb, void *data, uint32_t time, char *format, ...) +{ + int64_t flags; + work_container_t *container; + static char name[128]; + + va_list args; + va_start(args, format); + if (format) + DWC_VSNPRINTF(name, 128, format, args); + va_end(args); + + DWC_SPINLOCK_IRQSAVE(wq->lock, &flags); + wq->pending ++; + DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags); + DWC_WAITQ_TRIGGER(wq->waitq); + + container = DWC_ALLOC_ATOMIC(sizeof(*container)); + + container->data = data; + container->cb = work_cb; + container->wq = wq; + if (format) { //GRAYG + container->name = DWC_STRDUP(name); + DWC_DEBUG("Queueing work: %s, contianer=%p", + container->name, container); + } else + container->name = NULL; + INIT_DELAYED_WORK(&container->work, do_work); + +#ifdef DEBUG + DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry); +#endif + + queue_delayed_work(wq->wq, &container->work, msecs_to_jiffies(time)); + +} +EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE_DELAYED); + + +int DWC_WORKQ_PENDING(dwc_workq_t *wq) +{ + return wq->pending; +} +EXPORT_SYMBOL(DWC_WORKQ_PENDING); + +dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void) +{ + spinlock_t *sl = (spinlock_t *)1; +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP) + sl = DWC_ALLOC(sizeof(*sl)); + spin_lock_init(sl); +#endif + return (dwc_spinlock_t *)sl; +} +EXPORT_SYMBOL(DWC_SPINLOCK_ALLOC); + +void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock) +{ +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP) + DWC_FREE(lock); +#endif +} +EXPORT_SYMBOL(DWC_SPINLOCK_FREE); + +void DWC_SPINLOCK(dwc_spinlock_t *lock) +{ +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP) + spin_lock((spinlock_t *)lock); +#endif +} +EXPORT_SYMBOL(DWC_SPINLOCK); + +void DWC_SPINUNLOCK(dwc_spinlock_t *lock) +{ +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP) + spin_unlock((spinlock_t *)lock); +#endif +} +EXPORT_SYMBOL(DWC_SPINUNLOCK); + +void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, uint64_t *flags) +{ + unsigned long f; +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP) + spin_lock_irqsave((spinlock_t *)lock, f); +#else + local_irq_save(f); +#endif + *flags = f; +} +EXPORT_SYMBOL(DWC_SPINLOCK_IRQSAVE); + +void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, uint64_t flags) +{ +#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP) + spin_unlock_irqrestore((spinlock_t *)lock, flags); +#else + // in kernel 2.6.31, at least, we check for unsigned long + local_irq_restore((unsigned long)flags); +#endif +} +EXPORT_SYMBOL(DWC_SPINUNLOCK_IRQRESTORE); + +dwc_mutex_t *DWC_MUTEX_ALLOC(void) +{ + dwc_mutex_t *mutex = (dwc_mutex_t*)DWC_ALLOC(sizeof(struct mutex)); + struct mutex *m = (struct mutex *)mutex; + mutex_init(m); + return mutex; +} +EXPORT_SYMBOL(DWC_MUTEX_ALLOC); + +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)) +#else +void DWC_MUTEX_FREE(dwc_mutex_t *mutex) +{ + mutex_destroy((struct mutex *)mutex); + DWC_FREE(mutex); +} +EXPORT_SYMBOL(DWC_MUTEX_FREE); +#endif + +void DWC_MUTEX_LOCK(dwc_mutex_t *mutex) +{ + struct mutex *m = (struct mutex *)mutex; + mutex_lock(m); +} +EXPORT_SYMBOL(DWC_MUTEX_LOCK); + +int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex) +{ + struct mutex *m = (struct mutex *)mutex; + return mutex_trylock(m); +} +EXPORT_SYMBOL(DWC_MUTEX_TRYLOCK); + +void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex) +{ + struct mutex *m = (struct mutex *)mutex; + mutex_unlock(m); +} +EXPORT_SYMBOL(DWC_MUTEX_UNLOCK); + +dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t thread_function, char *name, void *data) +{ + struct task_struct *thread = kthread_run(thread_function, data, name); + if (thread == ERR_PTR(-ENOMEM)) { + return NULL; + } + return (dwc_thread_t *)thread; +} +EXPORT_SYMBOL(DWC_THREAD_RUN); + +int DWC_THREAD_STOP(dwc_thread_t *thread) +{ + return kthread_stop((struct task_struct *)thread); +} +EXPORT_SYMBOL(DWC_THREAD_STOP); + +dwc_bool_t DWC_THREAD_SHOULD_STOP() +{ + return kthread_should_stop(); +} +EXPORT_SYMBOL(DWC_THREAD_SHOULD_STOP); + +/* Timers */ + +struct dwc_timer +{ + struct timer_list *t; + char *name; + dwc_timer_callback_t cb; + void *data; + uint8_t scheduled; + dwc_spinlock_t *lock; +}; + +static void set_scheduled(dwc_timer_t *t, int s) +{ + uint64_t flags; + DWC_SPINLOCK_IRQSAVE(t->lock, &flags); + t->scheduled = s; + DWC_SPINUNLOCK_IRQRESTORE(t->lock, flags); +} + +static int get_scheduled(dwc_timer_t *t) +{ + int s; + uint64_t flags; + DWC_SPINLOCK_IRQSAVE(t->lock, &flags); + s = t->scheduled; + DWC_SPINUNLOCK_IRQRESTORE(t->lock, flags); + return s; +} + +static void timer_callback(unsigned long data) +{ + dwc_timer_t *timer = (dwc_timer_t *)data; + set_scheduled(timer, 0); + DWC_DEBUG("Timer %s callback", timer->name); + timer->cb(timer->data); +} + +dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data) +{ + dwc_timer_t *t = DWC_ALLOC(sizeof(*t)); + if (!t) { + DWC_ERROR("Cannot allocate memory for timer"); + return NULL; + } + t->t = DWC_ALLOC(sizeof(*t->t)); + if (!t->t) { + DWC_ERROR("Cannot allocate memory for timer->t"); + goto no_timer; + } + + t->name = DWC_STRDUP(name); + if (!t->name) { + DWC_ERROR("Cannot allocate memory for timer->name"); + goto no_name; + } + + t->lock = DWC_SPINLOCK_ALLOC(); + if (!t->lock) { + DWC_ERROR("Cannot allocate memory for lock"); + goto no_lock; + } + t->scheduled = 0; + t->t->base = &boot_tvec_bases; + t->t->expires = jiffies; + setup_timer(t->t, timer_callback, (unsigned long)t); + + t->cb = cb; + t->data = data; + + return t; + + no_lock: + DWC_FREE(t->name); + no_name: + DWC_FREE(t->t); + no_timer: + DWC_FREE(t); + return NULL; +} +EXPORT_SYMBOL(DWC_TIMER_ALLOC); + +void DWC_TIMER_FREE(dwc_timer_t *timer) +{ + if (get_scheduled(timer)) { + del_timer(timer->t); + } + + DWC_SPINLOCK_FREE(timer->lock); + DWC_FREE(timer->t); + DWC_FREE(timer->name); + DWC_FREE(timer); +} +EXPORT_SYMBOL(DWC_TIMER_FREE); + +void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time) +{ + if (!get_scheduled(timer)) { + set_scheduled(timer, 1); + //cgg: DWC_DEBUG("Scheduling timer %s to expire in +%d msec", timer->name, time); + timer->t->expires = jiffies + msecs_to_jiffies(time); + add_timer(timer->t); + } + else { + //cgg: DWC_DEBUG("Modifying timer %s to expire in +%d msec", timer->name, time); + mod_timer(timer->t, jiffies + msecs_to_jiffies(time)); + } +} +EXPORT_SYMBOL(DWC_TIMER_SCHEDULE); + +void DWC_TIMER_CANCEL(dwc_timer_t *timer) +{ + del_timer(timer->t); +} +EXPORT_SYMBOL(DWC_TIMER_CANCEL); + +struct dwc_tasklet +{ + struct tasklet_struct t; + dwc_tasklet_callback_t cb; + void *data; +}; + +static void tasklet_callback(unsigned long data) +{ + dwc_tasklet_t *t = (dwc_tasklet_t *)data; + t->cb(t->data); +} + +dwc_tasklet_t *DWC_TASK_ALLOC(dwc_tasklet_callback_t cb, void *data) +{ + dwc_tasklet_t *t = DWC_ALLOC(sizeof(*t)); + + if(t) { + t->data = data; + t->cb = cb; + tasklet_init(&t->t, tasklet_callback, (unsigned long)t); + } else { + DWC_ERROR("Cannot allocate memory for tasklet\n"); + } + + return t; +} +EXPORT_SYMBOL(DWC_TASK_ALLOC); + +void DWC_TASK_FREE(dwc_tasklet_t *t) +{ + DWC_FREE(t); +} +EXPORT_SYMBOL(DWC_TASK_FREE); + +void DWC_TASK_SCHEDULE(dwc_tasklet_t *task) +{ + tasklet_schedule(&task->t); +} +EXPORT_SYMBOL(DWC_TASK_SCHEDULE); + +/* Timing */ + +void DWC_UDELAY(uint32_t usecs) +{ + udelay(usecs); +} +EXPORT_SYMBOL(DWC_UDELAY); + +void DWC_MDELAY(uint32_t msecs) +{ + mdelay(msecs); +} +EXPORT_SYMBOL(DWC_MDELAY); + +void DWC_MSLEEP(uint32_t msecs) +{ + msleep(msecs); +} +EXPORT_SYMBOL(DWC_MSLEEP); + +uint32_t DWC_TIME(void) +{ + return jiffies_to_msecs(jiffies); +} +EXPORT_SYMBOL(DWC_TIME); + + +/* Wait Queues */ + +struct dwc_waitq +{ + wait_queue_head_t queue; + int abort; +}; + +dwc_waitq_t *DWC_WAITQ_ALLOC(void) +{ + dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq)); + init_waitqueue_head(&wq->queue); + wq->abort = 0; + return wq; +} +EXPORT_SYMBOL(DWC_WAITQ_ALLOC); + +void DWC_WAITQ_FREE(dwc_waitq_t *wq) +{ + DWC_FREE(wq); +} +EXPORT_SYMBOL(DWC_WAITQ_FREE); + +static int32_t check_result(dwc_waitq_t *wq, int result) +{ int32_t msecs; + if (result > 0) { + msecs = jiffies_to_msecs(result); + if (!msecs) { + return 1; + } + return msecs; + } + + if (result == 0) { + return -DWC_E_TIMEOUT; + } + + if ((result == -ERESTARTSYS) || (wq->abort == 1)) { + return -DWC_E_ABORT; + } + + return -DWC_E_UNKNOWN; +} + +int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t condition, void *data) +{ + int result = wait_event_interruptible(wq->queue, + condition(data) || wq->abort); + return check_result(wq, result); +} +EXPORT_SYMBOL(DWC_WAITQ_WAIT); + +int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t condition, + void *data, int32_t msecs) +{ + int result = wait_event_interruptible_timeout(wq->queue, + condition(data) || wq->abort, + msecs_to_jiffies(msecs)); + return check_result(wq, result); +} +EXPORT_SYMBOL(DWC_WAITQ_WAIT_TIMEOUT); + +void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq) +{ + wake_up_interruptible(&wq->queue); +} +EXPORT_SYMBOL(DWC_WAITQ_TRIGGER); + +void DWC_WAITQ_ABORT(dwc_waitq_t *wq) +{ + wq->abort = 1; + DWC_WAITQ_TRIGGER(wq); +} +EXPORT_SYMBOL(DWC_WAITQ_ABORT); diff --git a/drivers/usb/host/dwc_common_port/dwc_crypto.c b/drivers/usb/host/dwc_common_port/dwc_crypto.c new file mode 100644 index 000000000000..747840e653a2 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/dwc_crypto.c @@ -0,0 +1,306 @@ +/* ========================================================================= + * $File: //dwh/usb_iip/dev/software/dwc_common_port/dwc_crypto.c $ + * $Revision: #1 $ + * $Date: 2008/12/21 $ + * $Change: 1156609 $ + * + * Synopsys Portability Library Software and documentation + * (hereinafter, "Software") is an Unsupported proprietary work of + * Synopsys, Inc. unless otherwise expressly agreed to in writing + * between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product + * under any End User Software License Agreement or Agreement for + * Licensed Product with Synopsys or any supplement thereto. You are + * permitted to use and redistribute this Software in source and binary + * forms, with or without modification, provided that redistributions + * of source code must retain this notice. You may not view, use, + * disclose, copy or distribute this file or any information contained + * herein except pursuant to this license grant from Synopsys. If you + * do not agree with this notice, including the disclaimer below, then + * you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================= */ + +/** @file + * This file contains the WUSB cryptographic routines. + */ + +#include "dwc_crypto.h" +#include "usb.h" + +#ifdef DEBUG +static inline void dump_bytes(char *name, uint8_t *bytes, int len) +{ + int i; + DWC_PRINTF("%s: ", name); + for (i=0; idst == src, then the bytes will be encrypted + * in-place. + * + * @return 0 on success, negative error code on error. + */ +int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst) +{ + u8 block_t[16]; + DWC_MEMSET(block_t, 0, 16); + + return DWC_AES_CBC(src, 16, key, 16, block_t, dst); +} + +/** + * The CCM-MAC-FUNCTION described in section 6.5 of the WUSB spec. + * This function takes a data string and returns the encrypted CBC + * Counter-mode MIC. + * + * @param key The 128-bit symmetric key. + * @param nonce The CCM nonce. + * @param label The unique 14-byte ASCII text label. + * @param bytes The byte array to be encrypted. + * @param len Length of the byte array. + * @param result Byte array to receive the 8-byte encrypted MIC. + */ +void dwc_wusb_cmf(u8 *key, u8 *nonce, + char *label, u8 *bytes, int len, u8 *result) +{ + u8 block_m[16]; + u8 block_x[16]; + u8 block_t[8]; + int idx, blkNum; + u16 la = (u16)(len + 14); + + /* Set the AES-128 key */ + //dwc_aes_setkey(tfm, key, 16); + + /* Fill block B0 from flags = 0x59, N, and l(m) = 0 */ + block_m[0] = 0x59; + for (idx = 0; idx < 13; idx++) + block_m[idx + 1] = nonce[idx]; + block_m[14] = 0; + block_m[15] = 0; + + /* Produce the CBC IV */ + dwc_wusb_aes_encrypt(block_m, key, block_x); + show_block(block_m, "CBC IV in: ", "\n", 0); + show_block(block_x, "CBC IV out:", "\n", 0); + + /* Fill block B1 from l(a) = Blen + 14, and A */ + block_x[0] ^= (u8)(la >> 8); + block_x[1] ^= (u8)la; + for (idx = 0; idx < 14; idx++) + block_x[idx + 2] ^= label[idx]; + show_block(block_x, "After xor: ", "b1\n", 16); + + dwc_wusb_aes_encrypt(block_x, key, block_x); + show_block(block_x, "After AES: ", "b1\n", 16); + + idx = 0; + blkNum = 0; + + /* Fill remaining blocks with B */ + while (len-- > 0) { + block_x[idx] ^= *bytes++; + if (++idx >= 16) { + idx = 0; + show_block(block_x, "After xor: ", "\n", blkNum); + dwc_wusb_aes_encrypt(block_x, key, block_x); + show_block(block_x, "After AES: ", "\n", blkNum); + blkNum++; + } + } + + /* Handle partial last block */ + if (idx > 0) { + show_block(block_x, "After xor: ", "\n", blkNum); + dwc_wusb_aes_encrypt(block_x, key, block_x); + show_block(block_x, "After AES: ", "\n", blkNum); + } + + /* Save the MIC tag */ + DWC_MEMCPY(block_t, block_x, 8); + show_block(block_t, "MIC tag : ", NULL, 8); + + /* Fill block A0 from flags = 0x01, N, and counter = 0 */ + block_m[0] = 0x01; + block_m[14] = 0; + block_m[15] = 0; + + /* Encrypt the counter */ + dwc_wusb_aes_encrypt(block_m, key, block_x); + show_block(block_x, "CTR[MIC] : ", NULL, 8); + + /* XOR with MIC tag */ + for (idx = 0; idx < 8; idx++) { + block_t[idx] ^= block_x[idx]; + } + + /* Return result to caller */ + DWC_MEMCPY(result, block_t, 8); + show_block(result, "CCM-MIC : ", NULL, 8); + +} + +/** + * The PRF function described in section 6.5 of the WUSB spec. This function + * concatenates MIC values returned from dwc_cmf() to create a value of + * the requested length. + * + * @param prf_len Length of the PRF function in bits (64, 128, or 256). + * @param key, nonce, label, bytes, len Same as for dwc_cmf(). + * @param result Byte array to receive the result. + */ +void dwc_wusb_prf(int prf_len, u8 *key, + u8 *nonce, char *label, u8 *bytes, int len, u8 *result) +{ + int i; + + nonce[0] = 0; + for (i = 0; i < prf_len >> 6; i++, nonce[0]++) { + dwc_wusb_cmf(key, nonce, label, bytes, len, result); + result += 8; + } +} + +/** + * Fills in CCM Nonce per the WUSB spec. + * + * @param[in] haddr Host address. + * @param[in] daddr Device address. + * @param[in] tkid Session Key(PTK) identifier. + * @param[out] nonce Pointer to where the CCM Nonce output is to be written. + */ +void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid, + uint8_t *nonce) +{ + + DWC_DEBUG("%s %x %x\n", __func__, daddr, haddr); + + DWC_MEMSET(&nonce[0], 0, 16); + + DWC_MEMCPY(&nonce[6], tkid, 3); + nonce[9] = daddr & 0xFF; + nonce[10] = (daddr >> 8) & 0xFF; + nonce[11] = haddr & 0xFF; + nonce[12] = (haddr >> 8) & 0xFF; + + dump_bytes("CCM nonce", nonce, 16); +} + +/** + * Generates a 16-byte cryptographic-grade random number for the Host/Device + * Nonce. + */ +void dwc_wusb_gen_nonce(uint16_t addr, uint8_t *nonce) +{ + uint8_t inonce[16]; + uint32_t temp[4]; + + /* Fill in the Nonce */ + DWC_MEMSET(&inonce[0], 0, sizeof(inonce)); + inonce[9] = addr & 0xFF; + inonce[10] = (addr >> 8) & 0xFF; + inonce[11] = inonce[9]; + inonce[12] = inonce[10]; + + /* Collect "randomness samples" */ + DWC_RANDOM_BYTES((uint8_t *)temp, 16); + + dwc_wusb_prf_128((uint8_t *)temp, nonce, + "Random Numbers", (uint8_t *)temp, sizeof(temp), + nonce); +} + +/** + * Generates the Session Key (PTK) and Key Confirmation Key (KCK) per the + * WUSB spec. + * + * @param[in] ccm_nonce Pointer to CCM Nonce. + * @param[in] mk Master Key to derive the session from + * @param[in] hnonce Pointer to Host Nonce. + * @param[in] dnonce Pointer to Device Nonce. + * @param[out] kck Pointer to where the KCK output is to be written. + * @param[out] ptk Pointer to where the PTK output is to be written. + */ +void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk, uint8_t *hnonce, + uint8_t *dnonce, uint8_t *kck, uint8_t *ptk) +{ + uint8_t idata[32]; + uint8_t odata[32]; + + dump_bytes("ck", mk, 16); + dump_bytes("hnonce", hnonce, 16); + dump_bytes("dnonce", dnonce, 16); + + /* The data is the HNonce and DNonce concatenated */ + DWC_MEMCPY(&idata[0], hnonce, 16); + DWC_MEMCPY(&idata[16], dnonce, 16); + + dwc_wusb_prf_256(mk, ccm_nonce, "Pair-wise keys", idata, 32, odata); + + /* Low 16 bytes of the result is the KCK, high 16 is the PTK */ + DWC_MEMCPY(kck, &odata[0], 16); + DWC_MEMCPY(ptk, &odata[16], 16); + + dump_bytes("kck", kck, 16); + dump_bytes("ptk", ptk, 16); +} + +/** + * Generates the Message Integrity Code over the Handshake data per the + * WUSB spec. + * + * @param ccm_nonce Pointer to CCM Nonce. + * @param kck Pointer to Key Confirmation Key. + * @param data Pointer to Handshake data to be checked. + * @param mic Pointer to where the MIC output is to be written. + */ +void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t *kck, + uint8_t *data, uint8_t *mic) +{ + + dwc_wusb_prf_64(kck, ccm_nonce, "out-of-bandMIC", + data, WUSB_HANDSHAKE_LEN_FOR_MIC, mic); +} + diff --git a/drivers/usb/host/dwc_common_port/dwc_crypto.h b/drivers/usb/host/dwc_common_port/dwc_crypto.h new file mode 100644 index 000000000000..219d9619afd1 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/dwc_crypto.h @@ -0,0 +1,103 @@ +/* ========================================================================= + * $File: //dwh/usb_iip/dev/software/dwc_common_port/dwc_crypto.h $ + * $Revision: #1 $ + * $Date: 2008/12/21 $ + * $Change: 1156609 $ + * + * Synopsys Portability Library Software and documentation + * (hereinafter, "Software") is an Unsupported proprietary work of + * Synopsys, Inc. unless otherwise expressly agreed to in writing + * between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product + * under any End User Software License Agreement or Agreement for + * Licensed Product with Synopsys or any supplement thereto. You are + * permitted to use and redistribute this Software in source and binary + * forms, with or without modification, provided that redistributions + * of source code must retain this notice. You may not view, use, + * disclose, copy or distribute this file or any information contained + * herein except pursuant to this license grant from Synopsys. If you + * do not agree with this notice, including the disclaimer below, then + * you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================= */ + +#ifndef _DWC_CRYPTO_H_ +#define _DWC_CRYPTO_H_ + +/** @file + * + * This file contains declarations for the WUSB Cryptographic routines as + * defined in the WUSB spec. They are only to be used internally by the DWC UWB + * modules. + */ + +#include "dwc_os.h" + +int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst); + +void dwc_wusb_cmf(u8 *key, u8 *nonce, + char *label, u8 *bytes, int len, u8 *result); +void dwc_wusb_prf(int prf_len, u8 *key, + u8 *nonce, char *label, u8 *bytes, int len, u8 *result); + +/** + * The PRF-64 function described in section 6.5 of the WUSB spec. + * + * @param key, nonce, label, bytes, len, result Same as for dwc_prf(). + */ +static inline void dwc_wusb_prf_64(u8 *key, u8 *nonce, + char *label, u8 *bytes, int len, u8 *result) +{ + dwc_wusb_prf(64, key, nonce, label, bytes, len, result); +} + +/** + * The PRF-128 function described in section 6.5 of the WUSB spec. + * + * @param key, nonce, label, bytes, len, result Same as for dwc_prf(). + */ +static inline void dwc_wusb_prf_128(u8 *key, u8 *nonce, + char *label, u8 *bytes, int len, u8 *result) +{ + dwc_wusb_prf(128, key, nonce, label, bytes, len, result); +} + +/** + * The PRF-256 function described in section 6.5 of the WUSB spec. + * + * @param key, nonce, label, bytes, len, result Same as for dwc_prf(). + */ +static inline void dwc_wusb_prf_256(u8 *key, u8 *nonce, + char *label, u8 *bytes, int len, u8 *result) +{ + dwc_wusb_prf(256, key, nonce, label, bytes, len, result); +} + + +void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid, + uint8_t *nonce); +void dwc_wusb_gen_nonce(uint16_t addr, + uint8_t *nonce); + +void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk, + uint8_t *hnonce, uint8_t *dnonce, + uint8_t *kck, uint8_t *ptk); + + +void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t + *kck, uint8_t *data, uint8_t *mic); + +#endif /* _DWC_CRYPTO_H_ */ diff --git a/drivers/usb/host/dwc_common_port/dwc_dh.c b/drivers/usb/host/dwc_common_port/dwc_dh.c new file mode 100644 index 000000000000..9529b6a32341 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/dwc_dh.c @@ -0,0 +1,286 @@ +/* ========================================================================= + * $File: //dwh/usb_iip/dev/software/dwc_common_port/dwc_dh.c $ + * $Revision: #1 $ + * $Date: 2008/12/21 $ + * $Change: 1156609 $ + * + * Synopsys Portability Library Software and documentation + * (hereinafter, "Software") is an Unsupported proprietary work of + * Synopsys, Inc. unless otherwise expressly agreed to in writing + * between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product + * under any End User Software License Agreement or Agreement for + * Licensed Product with Synopsys or any supplement thereto. You are + * permitted to use and redistribute this Software in source and binary + * forms, with or without modification, provided that redistributions + * of source code must retain this notice. You may not view, use, + * disclose, copy or distribute this file or any information contained + * herein except pursuant to this license grant from Synopsys. If you + * do not agree with this notice, including the disclaimer below, then + * you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================= */ +#ifndef CONFIG_MACH_IPMATE +#include "dwc_dh.h" +#include "dwc_modpow.h" + +#ifdef DEBUG +/* This function prints out a buffer in the format described in the Association + * Model specification. */ +static void dh_dump(char *str, void *_num, int len) +{ + uint8_t *num = _num; + int i; + DWC_PRINTF("%s\n", str); + for (i = 0; i < len; i ++) { + DWC_PRINTF("%02x", num[i]); + if (((i + 1) % 2) == 0) DWC_PRINTF(" "); + if (((i + 1) % 26) == 0) DWC_PRINTF("\n"); + } + + DWC_PRINTF("\n"); +} +#else +#define dh_dump(_x...) do {; } while(0) +#endif + +/* Constant g value */ +static __u32 dh_g[] = { + 0x02000000, +}; + +/* Constant p value */ +static __u32 dh_p[] = { + 0xFFFFFFFF, 0xFFFFFFFF, 0xA2DA0FC9, 0x34C26821, 0x8B62C6C4, 0xD11CDC80, 0x084E0229, 0x74CC678A, + 0xA6BE0B02, 0x229B133B, 0x79084A51, 0xDD04348E, 0xB31995EF, 0x1B433ACD, 0x6D0A2B30, 0x37145FF2, + 0x6D35E14F, 0x45C2516D, 0x76B585E4, 0xC67E5E62, 0xE9424CF4, 0x6BED37A6, 0xB65CFF0B, 0xEDB706F4, + 0xFB6B38EE, 0xA59F895A, 0x11249FAE, 0xE61F4B7C, 0x51662849, 0x3D5BE4EC, 0xB87C00C2, 0x05BF63A1, + 0x3648DA98, 0x9AD3551C, 0xA83F1669, 0x5FCF24FD, 0x235D6583, 0x96ADA3DC, 0x56F3621C, 0xBB528520, + 0x0729D59E, 0x6D969670, 0x4E350C67, 0x0498BC4A, 0x086C74F1, 0x7C2118CA, 0x465E9032, 0x3BCE362E, + 0x2C779EE3, 0x03860E18, 0xA283279B, 0x8FA207EC, 0xF05DC5B5, 0xC9524C6F, 0xF6CB2BDE, 0x18175895, + 0x7C499539, 0xE56A95EA, 0x1826D215, 0x1005FA98, 0x5A8E7215, 0x2DC4AA8A, 0x0D1733AD, 0x337A5004, + 0xAB2155A8, 0x64BA1CDF, 0x0485FBEC, 0x0AEFDB58, 0x5771EA8A, 0x7D0C065D, 0x850F97B3, 0xC7E4E1A6, + 0x8CAEF5AB, 0xD73309DB, 0xE0948C1E, 0x9D61254A, 0x26D2E3CE, 0x6BEED21A, 0x06FA2FF1, 0x64088AD9, + 0x730276D8, 0x646AC83E, 0x182B1F52, 0x0C207B17, 0x5717E1BB, 0x6C5D617A, 0xC0880977, 0xE246D9BA, + 0xA04FE208, 0x31ABE574, 0xFC5BDB43, 0x8E10FDE0, 0x20D1824B, 0xCAD23AA9, 0xFFFFFFFF, 0xFFFFFFFF, +}; + +static void dh_swap_bytes(void *_in, void *_out, uint32_t len) +{ + uint8_t *in = _in; + uint8_t *out = _out; + int i; + for (i=0; inext = (link); \ + (link)->prev = (link); \ +} while(0) + +#define DWC_LIST_FIRST(link) ((link)->next) +#define DWC_LIST_LAST(link) ((link)->prev) +#define DWC_LIST_END(link) (link) +#define DWC_LIST_NEXT(link) ((link)->next) +#define DWC_LIST_PREV(link) ((link)->prev) +#define DWC_LIST_EMPTY(link) \ + (DWC_LIST_FIRST(link) == DWC_LIST_END(link)) +#define DWC_LIST_ENTRY(link, type, field) (type *) \ + ((uint8_t *)(link) - (size_t)(&((type *)0)->field)) + +#define DWC_LIST_INSERT_HEAD(list, link) do { \ + (link)->next = (list)->next; \ + (link)->prev = (list); \ + (list)->next->prev = link; \ + (list)->next = link; \ +} while(0) + +#define DWC_LIST_INSERT_TAIL(list, link) do { \ + (link)->next = list; \ + (link)->prev = (list)->prev; \ + (list)->prev->next = link; \ + (list)->prev = link; \ +} while(0) + +#define DWC_LIST_REMOVE(link) do { \ + (link)->next->prev = (link)->prev; \ + (link)->prev->next = (link)->next; \ +} while(0) + +#define DWC_LIST_REMOVE_INIT(link) do { \ + DWC_LIST_REMOVE(link); \ + DWC_LIST_INIT(link); \ +} while(0) + +#define DWC_LIST_MOVE_HEAD(list, link) do { \ + DWC_LIST_REMOVE(link); \ + DWC_LIST_INSERT_HEAD(list, link); \ +} while(0) + +#define DWC_LIST_MOVE_TAIL(list, link) do { \ + DWC_LIST_REMOVE(link); \ + DWC_LIST_INSERT_TAIL(list, link); \ +} while(0) + +#define DWC_LIST_FOREACH(var, list) \ + for((var) = DWC_LIST_FIRST(list); \ + (var) != DWC_LIST_END(list); \ + (var) = DWC_LIST_NEXT(var)) + +#define DWC_LIST_FOREACH_SAFE(var, var2, list) \ + for((var) = DWC_LIST_FIRST(list), var2 = DWC_LIST_NEXT(var); \ + (var) != DWC_LIST_END(list); \ + (var) = (var2), var2 = DWC_LIST_NEXT(var2)) + +#define DWC_LIST_FOREACH_REVERSE(var, list) \ + for((var) = DWC_LIST_LAST(list); \ + (var) != DWC_LIST_END(list); \ + (var) = DWC_LIST_PREV(var)) + +/* + * Singly-linked List definitions. + */ +#define DWC_SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define DWC_SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define DWC_SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List access methods. + */ +#define DWC_SLIST_FIRST(head) ((head)->slh_first) +#define DWC_SLIST_END(head) NULL +#define DWC_SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) +#define DWC_SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define DWC_SLIST_FOREACH(var, head, field) \ + for((var) = SLIST_FIRST(head); \ + (var) != SLIST_END(head); \ + (var) = SLIST_NEXT(var, field)) + +#define DWC_SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != SLIST_END(head); \ + (varp) = &SLIST_NEXT((var), field)) + +/* + * Singly-linked List functions. + */ +#define DWC_SLIST_INIT(head) { \ + SLIST_FIRST(head) = SLIST_END(head); \ +} + +#define DWC_SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define DWC_SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define DWC_SLIST_REMOVE_NEXT(head, elm, field) do { \ + (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ +} while (0) + +#define DWC_SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +#define DWC_SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = (head)->slh_first; \ + while( curelm->field.sle_next != (elm) ) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + } \ +} while (0) + +#if 0 + +/* + * List definitions. + */ +#define DWC_LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define DWC_LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define DWC_LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods + */ +#define DWC_LIST_FIRST(head) ((head)->lh_first) +#define DWC_LIST_END(head) NULL +#define DWC_LIST_EMPTY(head) (DWC_LIST_FIRST(head) == DWC_LIST_END(head)) +#define DWC_LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define DWC_LIST_FOREACH(var, head, field) \ + for((var) = DWC_LIST_FIRST(head); \ + (var)!= DWC_LIST_END(head); \ + (var) = DWC_LIST_NEXT(var, field)) +#define DWC_LIST_FOREACH_SAFE(var, var2, head, field) \ + for((var) = DWC_LIST_FIRST(head), var2 = DWC_LIST_NEXT(var, field); \ + (var) != DWC_LIST_END(head); \ + (var) = var2, var2 = DWC_LIST_NEXT(var, field)) + +/* + * List functions. + */ +#define DWC_LIST_INIT(head) do { \ + DWC_LIST_FIRST(head) = DWC_LIST_END(head); \ +} while (0) + +#define DWC_LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define DWC_LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define DWC_LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define DWC_LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ +} while (0) + +#define DWC_LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ +} while (0) + +#endif + +/* + * Simple queue definitions. + */ +#define DWC_SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define DWC_SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define DWC_SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue access methods. + */ +#define DWC_SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define DWC_SIMPLEQ_END(head) NULL +#define DWC_SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) +#define DWC_SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define DWC_SIMPLEQ_FOREACH(var, head, field) \ + for((var) = SIMPLEQ_FIRST(head); \ + (var) != SIMPLEQ_END(head); \ + (var) = SIMPLEQ_NEXT(var, field)) + +/* + * Simple queue functions. + */ +#define DWC_SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define DWC_SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define DWC_SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define DWC_SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define DWC_SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +/* + * Tail queue definitions. + */ +#define DWC_TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define DWC_TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define DWC_TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * tail queue access methods + */ +#define DWC_TAILQ_FIRST(head) ((head)->tqh_first) +#define DWC_TAILQ_END(head) NULL +#define DWC_TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define DWC_TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* XXX */ +#define DWC_TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define DWC_TAILQ_EMPTY(head) \ + (TAILQ_FIRST(head) == TAILQ_END(head)) + +#define DWC_TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) + +#define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_PREV(var, headname, field)) + +/* + * Tail queue functions. + */ +#define DWC_TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define DWC_TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define DWC_TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define DWC_TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define DWC_TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define DWC_TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ +} while (0) + +#define DWC_TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ +} while (0) + +/* + * Circular queue definitions. + */ +#define DWC_CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define DWC_CIRCLEQ_HEAD_INITIALIZER(head) \ + { DWC_CIRCLEQ_END(&head), DWC_CIRCLEQ_END(&head) } + +#define DWC_CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue access methods + */ +#define DWC_CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define DWC_CIRCLEQ_LAST(head) ((head)->cqh_last) +#define DWC_CIRCLEQ_END(head) ((void *)(head)) +#define DWC_CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define DWC_CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#define DWC_CIRCLEQ_EMPTY(head) \ + (DWC_CIRCLEQ_FIRST(head) == DWC_CIRCLEQ_END(head)) + +#define DWC_CIRCLEQ_EMPTY_ENTRY(elm, field) (((elm)->field.cqe_next == NULL) && ((elm)->field.cqe_prev == NULL)) + +#define DWC_CIRCLEQ_FOREACH(var, head, field) \ + for((var) = DWC_CIRCLEQ_FIRST(head); \ + (var) != DWC_CIRCLEQ_END(head); \ + (var) = DWC_CIRCLEQ_NEXT(var, field)) + +#define DWC_CIRCLEQ_FOREACH_SAFE(var, var2, head, field) \ + for((var) = DWC_CIRCLEQ_FIRST(head), var2 = DWC_CIRCLEQ_NEXT(var, field); \ + (var) != DWC_CIRCLEQ_END(head); \ + (var) = var2, var2 = DWC_CIRCLEQ_NEXT(var, field)) + +#define DWC_CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for((var) = DWC_CIRCLEQ_LAST(head); \ + (var) != DWC_CIRCLEQ_END(head); \ + (var) = DWC_CIRCLEQ_PREV(var, field)) + +/* + * Circular queue functions. + */ +#define DWC_CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = DWC_CIRCLEQ_END(head); \ + (head)->cqh_last = DWC_CIRCLEQ_END(head); \ +} while (0) + +#define DWC_CIRCLEQ_INIT_ENTRY(elm, field) do { \ + (elm)->field.cqe_next = NULL; \ + (elm)->field.cqe_prev = NULL; \ +} while (0) + +#define DWC_CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == DWC_CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define DWC_CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == DWC_CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define DWC_CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = DWC_CIRCLEQ_END(head); \ + if ((head)->cqh_last == DWC_CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define DWC_CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = DWC_CIRCLEQ_END(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == DWC_CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define DWC_CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == DWC_CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == DWC_CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ +} while (0) + +#define DWC_CIRCLEQ_REMOVE_INIT(head, elm, field) do { \ + DWC_CIRCLEQ_REMOVE(head, elm, field); \ + DWC_CIRCLEQ_INIT_ENTRY(elm, field); \ +} while (0) + +#define DWC_CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ + DWC_CIRCLEQ_END(head)) \ + (head).cqh_last = (elm2); \ + else \ + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ + DWC_CIRCLEQ_END(head)) \ + (head).cqh_first = (elm2); \ + else \ + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/drivers/usb/host/dwc_common_port/dwc_mem.c b/drivers/usb/host/dwc_common_port/dwc_mem.c new file mode 100644 index 000000000000..f2f9bc694d21 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/dwc_mem.c @@ -0,0 +1,172 @@ +#include "dwc_os.h" +#include "dwc_list.h" + +/* Memory Debugging */ +#ifdef DEBUG_MEMORY + +struct allocation +{ + void *addr; + char *func; + int line; + uint32_t size; + int dma; + DWC_CIRCLEQ_ENTRY(allocation) entry; +}; + +DWC_CIRCLEQ_HEAD(allocation_queue, allocation); + +struct allocation_manager +{ + struct allocation_queue allocations; + + /* statistics */ + int num; + int num_freed; + int num_active; + uint32_t total; + uint32_t current; + uint32_t max; +}; + + +static struct allocation_manager *manager = NULL; + +static void add_allocation(uint32_t size, char const* func, int line, void *addr, int dma) +{ + struct allocation *a = __DWC_ALLOC_ATOMIC(sizeof(*a)); + a->func = __DWC_ALLOC_ATOMIC(DWC_STRLEN(func)+1); + DWC_MEMCPY(a->func, func, DWC_STRLEN(func)+1); + a->line = line; + a->size = size; + a->addr = addr; + a->dma = dma; + DWC_CIRCLEQ_INSERT_TAIL(&manager->allocations, a, entry); + + /* Update stats */ + manager->num ++; + manager->num_active ++; + manager->total += size; + manager->current += size; + if (manager->max < manager->current) { + manager->max = manager->current; + } +} + +static struct allocation *find_allocation(void *addr) +{ + struct allocation *a; + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) { + if (a->addr == addr) { + return a; + } + } + return NULL; +} + +static void free_allocation(void *addr, char const* func, int line) +{ + struct allocation *a = find_allocation(addr); + if (!a && func && (line >= 0)) { + DWC_ASSERT(0, "Free of address %p that was never allocated or already freed %s:%d", addr, func, line); + return; + } + DWC_CIRCLEQ_REMOVE(&manager->allocations, a, entry); + + manager->num_active --; + manager->num_freed ++; + manager->current -= a->size; + __DWC_FREE(a->func); + __DWC_FREE(a); +} + +void dwc_memory_debug_start(void) +{ + DWC_ASSERT(manager == NULL, "Memory debugging has already started\n"); + if (manager == NULL) { + manager = __DWC_ALLOC(sizeof(*manager)); + } + + DWC_CIRCLEQ_INIT(&manager->allocations); + manager->num = 0; + manager->num_freed = 0; + manager->num_active = 0; + manager->total = 0; + manager->current = 0; + manager->max = 0; +} + +void dwc_memory_debug_stop(void) +{ + struct allocation *a; + dwc_memory_debug_report(); + + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) { + DWC_ERROR("Memory leaked from %s:%d\n", a->func, a->line); + free_allocation(a->addr, NULL, -1); + } + + __DWC_FREE(manager); +} + +void dwc_memory_debug_report(void) +{ + struct allocation *a; + DWC_PRINTF("\n\n\n----------------- Memory Debugging Report -----------------\n\n"); + DWC_PRINTF("Num Allocations = %d\n", manager->num); + DWC_PRINTF("Freed = %d\n", manager->num_freed); + DWC_PRINTF("Active = %d\n", manager->num_active); + DWC_PRINTF("Current Memory Used = %d\n", manager->current); + DWC_PRINTF("Total Memory Used = %d\n", manager->total); + DWC_PRINTF("Maximum Memory Used at Once = %d\n", manager->max); + DWC_PRINTF("Unfreed allocations:\n"); + + DWC_CIRCLEQ_FOREACH(a, &manager->allocations, entry) { + DWC_PRINTF(" addr=%p, size=%d from %s:%d, DMA=%d\n", a->addr, a->size, a->func, a->line, a->dma); + } +} + + + +/* The replacement functions */ +void *dwc_alloc_debug(uint32_t size, char const* func, int line) +{ + void *addr = __DWC_ALLOC(size); + add_allocation(size, func, line, addr, 0); + return addr; +} + +void *dwc_alloc_atomic_debug(uint32_t size, char const* func, int line) +{ + void *addr = __DWC_ALLOC_ATOMIC(size); + add_allocation(size, func, line, addr, 0); + return addr; +} + +void dwc_free_debug(void *addr, char const* func, int line) +{ + free_allocation(addr, func, line); + __DWC_FREE(addr); +} + +void *dwc_dma_alloc_debug(uint32_t size, dwc_dma_t *dma_addr, char const *func, int line) +{ + void *addr = __DWC_DMA_ALLOC(size, dma_addr); + add_allocation(size, func, line, addr, 1); + return addr; +} + +void *dwc_dma_alloc_atomic_debug(uint32_t size, dwc_dma_t *dma_addr, char const *func, int line) +{ + void *addr = __DWC_DMA_ALLOC_ATOMIC(size, dma_addr); + add_allocation(size, func, line, addr, 1); + return addr; +} + +void dwc_dma_free_debug(uint32_t size, void *virt_addr, dwc_dma_t dma_addr, char const *func, int line) +{ + free_allocation(virt_addr, func, line); + __DWC_DMA_FREE(size, virt_addr, dma_addr); +} + +#endif /* DEBUG_MEMORY */ diff --git a/drivers/usb/host/dwc_common_port/dwc_modpow.c b/drivers/usb/host/dwc_common_port/dwc_modpow.c new file mode 100644 index 000000000000..563332d0c9e4 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/dwc_modpow.c @@ -0,0 +1,622 @@ +/* Bignum routines adapted from PUTTY sources. PuTTY copyright notice follows. + * + * PuTTY is copyright 1997-2007 Simon Tatham. + * + * Portions copyright Robert de Bath, Joris van Rantwijk, Delian + * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry, + * Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus + * Kuhn, and CORE SDI S.A. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef CONFIG_MACH_IPMATE + + +#include "dwc_modpow.h" + +#define BIGNUM_INT_MASK 0xFFFFFFFFUL +#define BIGNUM_TOP_BIT 0x80000000UL +#define BIGNUM_INT_BITS 32 + + +static void *snmalloc(size_t n, size_t size) +{ + void *p; + size *= n; + if (size == 0) size = 1; + p = DWC_ALLOC(size); + return p; +} + +#define snewn(n, type) ((type *)snmalloc((n), sizeof(type))) +#define sfree DWC_FREE + +/* + * Usage notes: + * * Do not call the DIVMOD_WORD macro with expressions such as array + * subscripts, as some implementations object to this (see below). + * * Note that none of the division methods below will cope if the + * quotient won't fit into BIGNUM_INT_BITS. Callers should be careful + * to avoid this case. + * If this condition occurs, in the case of the x86 DIV instruction, + * an overflow exception will occur, which (according to a correspondent) + * will manifest on Windows as something like + * 0xC0000095: Integer overflow + * The C variant won't give the right answer, either. + */ + +#define MUL_WORD(w1, w2) ((BignumDblInt)w1 * w2) + +#if defined __GNUC__ && defined __i386__ +#define DIVMOD_WORD(q, r, hi, lo, w) \ + __asm__("div %2" : \ + "=d" (r), "=a" (q) : \ + "r" (w), "d" (hi), "a" (lo)) +#else +#define DIVMOD_WORD(q, r, hi, lo, w) do { \ + BignumDblInt n = (((BignumDblInt)hi) << BIGNUM_INT_BITS) | lo; \ + q = n / w; \ + r = n % w; \ +} while (0) +#endif + +// q = n / w; +// r = n % w; + +#define BIGNUM_INT_BYTES (BIGNUM_INT_BITS / 8) + +#define BIGNUM_INTERNAL + +static Bignum newbn(int length) +{ + Bignum b = snewn(length + 1, BignumInt); + //if (!b) + //abort(); /* FIXME */ + DWC_MEMSET(b, 0, (length + 1) * sizeof(*b)); + b[0] = length; + return b; +} + +void freebn(Bignum b) +{ + /* + * Burn the evidence, just in case. + */ + DWC_MEMSET(b, 0, sizeof(b[0]) * (b[0] + 1)); + sfree(b); +} + +/* + * Compute c = a * b. + * Input is in the first len words of a and b. + * Result is returned in the first 2*len words of c. + */ +static void internal_mul(BignumInt *a, BignumInt *b, + BignumInt *c, int len) +{ + int i, j; + BignumDblInt t; + + for (j = 0; j < 2 * len; j++) + c[j] = 0; + + for (i = len - 1; i >= 0; i--) { + t = 0; + for (j = len - 1; j >= 0; j--) { + t += MUL_WORD(a[i], (BignumDblInt) b[j]); + t += (BignumDblInt) c[i + j + 1]; + c[i + j + 1] = (BignumInt) t; + t = t >> BIGNUM_INT_BITS; + } + c[i] = (BignumInt) t; + } +} + +static void internal_add_shifted(BignumInt *number, + unsigned n, int shift) +{ + int word = 1 + (shift / BIGNUM_INT_BITS); + int bshift = shift % BIGNUM_INT_BITS; + BignumDblInt addend; + + addend = (BignumDblInt)n << bshift; + + while (addend) { + addend += number[word]; + number[word] = (BignumInt) addend & BIGNUM_INT_MASK; + addend >>= BIGNUM_INT_BITS; + word++; + } +} + +/* + * Compute a = a % m. + * Input in first alen words of a and first mlen words of m. + * Output in first alen words of a + * (of which first alen-mlen words will be zero). + * The MSW of m MUST have its high bit set. + * Quotient is accumulated in the `quotient' array, which is a Bignum + * rather than the internal bigendian format. Quotient parts are shifted + * left by `qshift' before adding into quot. + */ +static void internal_mod(BignumInt *a, int alen, + BignumInt *m, int mlen, + BignumInt *quot, int qshift) +{ + BignumInt m0, m1; + unsigned int h; + int i, k; + + m0 = m[0]; + if (mlen > 1) + m1 = m[1]; + else + m1 = 0; + + for (i = 0; i <= alen - mlen; i++) { + BignumDblInt t; + unsigned int q, r, c, ai1; + + if (i == 0) { + h = 0; + } else { + h = a[i - 1]; + a[i - 1] = 0; + } + + if (i == alen - 1) + ai1 = 0; + else + ai1 = a[i + 1]; + + /* Find q = h:a[i] / m0 */ + if (h >= m0) { + /* + * Special case. + * + * To illustrate it, suppose a BignumInt is 8 bits, and + * we are dividing (say) A1:23:45:67 by A1:B2:C3. Then + * our initial division will be 0xA123 / 0xA1, which + * will give a quotient of 0x100 and a divide overflow. + * However, the invariants in this division algorithm + * are not violated, since the full number A1:23:... is + * _less_ than the quotient prefix A1:B2:... and so the + * following correction loop would have sorted it out. + * + * In this situation we set q to be the largest + * quotient we _can_ stomach (0xFF, of course). + */ + q = BIGNUM_INT_MASK; + } else { + /* Macro doesn't want an array subscript expression passed + * into it (see definition), so use a temporary. */ + BignumInt tmplo = a[i]; + DIVMOD_WORD(q, r, h, tmplo, m0); + + /* Refine our estimate of q by looking at + h:a[i]:a[i+1] / m0:m1 */ + t = MUL_WORD(m1, q); + if (t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) { + q--; + t -= m1; + r = (r + m0) & BIGNUM_INT_MASK; /* overflow? */ + if (r >= (BignumDblInt) m0 && + t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) q--; + } + } + + /* Subtract q * m from a[i...] */ + c = 0; + for (k = mlen - 1; k >= 0; k--) { + t = MUL_WORD(q, m[k]); + t += c; + c = (unsigned)(t >> BIGNUM_INT_BITS); + if ((BignumInt) t > a[i + k]) + c++; + a[i + k] -= (BignumInt) t; + } + + /* Add back m in case of borrow */ + if (c != h) { + t = 0; + for (k = mlen - 1; k >= 0; k--) { + t += m[k]; + t += a[i + k]; + a[i + k] = (BignumInt) t; + t = t >> BIGNUM_INT_BITS; + } + q--; + } + if (quot) + internal_add_shifted(quot, q, qshift + BIGNUM_INT_BITS * (alen - mlen - i)); + } +} + +/* + * Compute p % mod. + * The most significant word of mod MUST be non-zero. + * We assume that the result array is the same size as the mod array. + * We optionally write out a quotient if `quotient' is non-NULL. + * We can avoid writing out the result if `result' is NULL. + */ +void bigdivmod(Bignum p, Bignum mod, Bignum result, Bignum quotient) +{ + BignumInt *n, *m; + int mshift; + int plen, mlen, i, j; + + /* Allocate m of size mlen, copy mod to m */ + /* We use big endian internally */ + mlen = mod[0]; + m = snewn(mlen, BignumInt); + for (j = 0; j < mlen; j++) + m[j] = mod[mod[0] - j]; + + /* Shift m left to make msb bit set */ + for (mshift = 0; mshift < BIGNUM_INT_BITS-1; mshift++) + if ((m[0] << mshift) & BIGNUM_TOP_BIT) + break; + if (mshift) { + for (i = 0; i < mlen - 1; i++) + m[i] = (m[i] << mshift) | (m[i + 1] >> (BIGNUM_INT_BITS - mshift)); + m[mlen - 1] = m[mlen - 1] << mshift; + } + + plen = p[0]; + /* Ensure plen > mlen */ + if (plen <= mlen) + plen = mlen + 1; + + /* Allocate n of size plen, copy p to n */ + n = snewn(plen, BignumInt); + for (j = 0; j < plen; j++) + n[j] = 0; + for (j = 1; j <= (int)p[0]; j++) + n[plen - j] = p[j]; + + /* Main computation */ + internal_mod(n, plen, m, mlen, quotient, mshift); + + /* Fixup result in case the modulus was shifted */ + if (mshift) { + for (i = plen - mlen - 1; i < plen - 1; i++) + n[i] = (n[i] << mshift) | (n[i + 1] >> (BIGNUM_INT_BITS - mshift)); + n[plen - 1] = n[plen - 1] << mshift; + internal_mod(n, plen, m, mlen, quotient, 0); + for (i = plen - 1; i >= plen - mlen; i--) + n[i] = (n[i] >> mshift) | (n[i - 1] << (BIGNUM_INT_BITS - mshift)); + } + + /* Copy result to buffer */ + if (result) { + for (i = 1; i <= (int)result[0]; i++) { + int j = plen - i; + result[i] = j >= 0 ? n[j] : 0; + } + } + + /* Free temporary arrays */ + for (i = 0; i < mlen; i++) + m[i] = 0; + sfree(m); + for (i = 0; i < plen; i++) + n[i] = 0; + sfree(n); +} + +/* + * Simple remainder. + */ +Bignum bigmod(Bignum a, Bignum b) +{ + Bignum r = newbn(b[0]); + bigdivmod(a, b, r, NULL); + return r; +} + +/* + * Compute (base ^ exp) % mod. + */ +Bignum dwc_modpow(Bignum base_in, Bignum exp, Bignum mod) +{ + BignumInt *a, *b, *n, *m; + int mshift; + int mlen, i, j; + Bignum base, result; + + /* + * The most significant word of mod needs to be non-zero. It + * should already be, but let's make sure. + */ + //assert(mod[mod[0]] != 0); + + /* + * Make sure the base is smaller than the modulus, by reducing + * it modulo the modulus if not. + */ + base = bigmod(base_in, mod); + + /* Allocate m of size mlen, copy mod to m */ + /* We use big endian internally */ + mlen = mod[0]; + m = snewn(mlen, BignumInt); + for (j = 0; j < mlen; j++) + m[j] = mod[mod[0] - j]; + + /* Shift m left to make msb bit set */ + for (mshift = 0; mshift < BIGNUM_INT_BITS - 1; mshift++) + if ((m[0] << mshift) & BIGNUM_TOP_BIT) + break; + if (mshift) { + for (i = 0; i < mlen - 1; i++) + m[i] = + (m[i] << mshift) | (m[i + 1] >> + (BIGNUM_INT_BITS - mshift)); + m[mlen - 1] = m[mlen - 1] << mshift; + } + + /* Allocate n of size mlen, copy base to n */ + n = snewn(mlen, BignumInt); + i = mlen - base[0]; + for (j = 0; j < i; j++) + n[j] = 0; + for (j = 0; j < base[0]; j++) + n[i + j] = base[base[0] - j]; + + /* Allocate a and b of size 2*mlen. Set a = 1 */ + a = snewn(2 * mlen, BignumInt); + b = snewn(2 * mlen, BignumInt); + for (i = 0; i < 2 * mlen; i++) + a[i] = 0; + a[2 * mlen - 1] = 1; + + /* Skip leading zero bits of exp. */ + i = 0; + j = BIGNUM_INT_BITS - 1; + while (i < exp[0] && (exp[exp[0] - i] & (1 << j)) == 0) { + j--; + if (j < 0) { + i++; + j = BIGNUM_INT_BITS - 1; + } + } + + /* Main computation */ + while (i < exp[0]) { + while (j >= 0) { + internal_mul(a + mlen, a + mlen, b, mlen); + internal_mod(b, mlen * 2, m, mlen, NULL, 0); + if ((exp[exp[0] - i] & (1 << j)) != 0) { + internal_mul(b + mlen, n, a, mlen); + internal_mod(a, mlen * 2, m, mlen, NULL, 0); + } else { + BignumInt *t; + t = a; + a = b; + b = t; + } + j--; + } + i++; + j = BIGNUM_INT_BITS - 1; + } + + /* Fixup result in case the modulus was shifted */ + if (mshift) { + for (i = mlen - 1; i < 2 * mlen - 1; i++) + a[i] = + (a[i] << mshift) | (a[i + 1] >> + (BIGNUM_INT_BITS - mshift)); + a[2 * mlen - 1] = a[2 * mlen - 1] << mshift; + internal_mod(a, mlen * 2, m, mlen, NULL, 0); + for (i = 2 * mlen - 1; i >= mlen; i--) + a[i] = + (a[i] >> mshift) | (a[i - 1] << + (BIGNUM_INT_BITS - mshift)); + } + + /* Copy result to buffer */ + result = newbn(mod[0]); + for (i = 0; i < mlen; i++) + result[result[0] - i] = a[i + mlen]; + while (result[0] > 1 && result[result[0]] == 0) + result[0]--; + + /* Free temporary arrays */ + for (i = 0; i < 2 * mlen; i++) + a[i] = 0; + sfree(a); + for (i = 0; i < 2 * mlen; i++) + b[i] = 0; + sfree(b); + for (i = 0; i < mlen; i++) + m[i] = 0; + sfree(m); + for (i = 0; i < mlen; i++) + n[i] = 0; + sfree(n); + + freebn(base); + + return result; +} + + +#ifdef UNITTEST + +static __u32 dh_p[] = { + 96, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xA93AD2CA, + 0x4B82D120, + 0xE0FD108E, + 0x43DB5BFC, + 0x74E5AB31, + 0x08E24FA0, + 0xBAD946E2, + 0x770988C0, + 0x7A615D6C, + 0xBBE11757, + 0x177B200C, + 0x521F2B18, + 0x3EC86A64, + 0xD8760273, + 0xD98A0864, + 0xF12FFA06, + 0x1AD2EE6B, + 0xCEE3D226, + 0x4A25619D, + 0x1E8C94E0, + 0xDB0933D7, + 0xABF5AE8C, + 0xA6E1E4C7, + 0xB3970F85, + 0x5D060C7D, + 0x8AEA7157, + 0x58DBEF0A, + 0xECFB8504, + 0xDF1CBA64, + 0xA85521AB, + 0x04507A33, + 0xAD33170D, + 0x8AAAC42D, + 0x15728E5A, + 0x98FA0510, + 0x15D22618, + 0xEA956AE5, + 0x3995497C, + 0x95581718, + 0xDE2BCBF6, + 0x6F4C52C9, + 0xB5C55DF0, + 0xEC07A28F, + 0x9B2783A2, + 0x180E8603, + 0xE39E772C, + 0x2E36CE3B, + 0x32905E46, + 0xCA18217C, + 0xF1746C08, + 0x4ABC9804, + 0x670C354E, + 0x7096966D, + 0x9ED52907, + 0x208552BB, + 0x1C62F356, + 0xDCA3AD96, + 0x83655D23, + 0xFD24CF5F, + 0x69163FA8, + 0x1C55D39A, + 0x98DA4836, + 0xA163BF05, + 0xC2007CB8, + 0xECE45B3D, + 0x49286651, + 0x7C4B1FE6, + 0xAE9F2411, + 0x5A899FA5, + 0xEE386BFB, + 0xF406B7ED, + 0x0BFF5CB6, + 0xA637ED6B, + 0xF44C42E9, + 0x625E7EC6, + 0xE485B576, + 0x6D51C245, + 0x4FE1356D, + 0xF25F1437, + 0x302B0A6D, + 0xCD3A431B, + 0xEF9519B3, + 0x8E3404DD, + 0x514A0879, + 0x3B139B22, + 0x020BBEA6, + 0x8A67CC74, + 0x29024E08, + 0x80DC1CD1, + 0xC4C6628B, + 0x2168C234, + 0xC90FDAA2, + 0xFFFFFFFF, + 0xFFFFFFFF, +}; + +static __u32 dh_a[] = { + 8, + 0xdf367516, + 0x86459caa, + 0xe2d459a4, + 0xd910dae0, + 0x8a8b5e37, + 0x67ab31c6, + 0xf0b55ea9, + 0x440051d6, +}; + +static __u32 dh_b[] = { + 8, + 0xded92656, + 0xe07a048a, + 0x6fa452cd, + 0x2df89d30, + 0xc75f1b0f, + 0x8ce3578f, + 0x7980a324, + 0x5daec786, +}; + +static __u32 dh_g[] = { + 1, + 2, +}; + +int main(void) +{ + int i; + __u32 *k; + k = modpow(dh_g, dh_a, dh_p); + + printf("\n\n"); + for (i=0; i> 16; + printf("%04x %04x ", m, l); + if (!((i + 1)%13)) printf("\n"); + } + printf("\n\n"); + + if ((k[0] == 0x60) && (k[1] == 0x28e490e5) && (k[0x60] == 0x5a0d3d4e)) { + printf("PASS\n\n"); + } + else { + printf("FAIL\n\n"); + } + +} + +#endif /* UNITTEST */ + +#endif /* CONFIG_MACH_IPMATE */ diff --git a/drivers/usb/host/dwc_common_port/dwc_modpow.h b/drivers/usb/host/dwc_common_port/dwc_modpow.h new file mode 100644 index 000000000000..980f9f14f041 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/dwc_modpow.h @@ -0,0 +1,26 @@ +/* + * dwc_modpow.h + * See dwc_modpow.c for license and changes + */ +#ifndef _DWC_MODPOW_H +#define _DWC_MODPOW_H + +#include "dwc_os.h" + +/** @file + * + * This file defines the module exponentiation function which is only used + * internally by the DWC UWB modules for calculation of PKs during numeric + * association. The routine is taken from the PUTTY, an open source terminal + * emulator. The PUTTY License is preserved in the dwc_modpow.c file. + * + */ + +typedef uint32_t BignumInt; +typedef uint64_t BignumDblInt; +typedef BignumInt *Bignum; + +/* Compute modular exponentiaion */ +extern Bignum dwc_modpow(Bignum base_in, Bignum exp, Bignum mod); + +#endif /* _LINUX_BIGNUM_H */ diff --git a/drivers/usb/host/dwc_common_port/dwc_notifier.c b/drivers/usb/host/dwc_common_port/dwc_notifier.c new file mode 100644 index 000000000000..e44bb81dbc46 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/dwc_notifier.c @@ -0,0 +1,256 @@ +#include "dwc_notifier.h" +#include "dwc_list.h" + +typedef struct dwc_observer +{ + void *observer; + dwc_notifier_callback_t callback; + void *data; + char *notification; + DWC_CIRCLEQ_ENTRY(dwc_observer) list_entry; +} observer_t; + +DWC_CIRCLEQ_HEAD(observer_queue, dwc_observer); + +typedef struct dwc_notifier +{ + void *object; + struct observer_queue observers; + DWC_CIRCLEQ_ENTRY(dwc_notifier) list_entry; +} notifier_t; + +DWC_CIRCLEQ_HEAD(notifier_queue, dwc_notifier); + +typedef struct manager +{ + dwc_workq_t *wq; + dwc_mutex_t *mutex; + struct notifier_queue notifiers; +} manager_t; + +static manager_t *manager = NULL; + +static void create_manager(void) +{ + manager = DWC_ALLOC(sizeof(manager_t)); + DWC_CIRCLEQ_INIT(&manager->notifiers); + manager->wq = DWC_WORKQ_ALLOC("DWC Notification WorkQ"); +} + +static void free_manager(void) +{ + DWC_WORKQ_FREE(manager->wq); + /* All notifiers must have unregistered themselves before this module + * can be removed. Hitting this assertion indicates a programmer + * error. */ + DWC_ASSERT(DWC_CIRCLEQ_EMPTY(&manager->notifiers), "Notification manager being freed before all notifiers have been removed"); + DWC_FREE(manager); +} + +#ifdef DEBUG +static void dump_manager(void) +{ + notifier_t *n; + observer_t *o; + DWC_ASSERT(manager, "Notification manager not found"); + DWC_DEBUG("List of all notifiers and observers:"); + DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) { + DWC_DEBUG("Notifier %p has observers:", n->object); + DWC_CIRCLEQ_FOREACH(o, &n->observers, list_entry) { + DWC_DEBUG(" %p watching %s", o->observer, o->notification); + } + } +} +#else +#define dump_manager(...) +#endif + +static observer_t *alloc_observer(void *observer, char *notification, dwc_notifier_callback_t callback, void *data) +{ + observer_t *new_observer = DWC_ALLOC(sizeof(observer_t)); + DWC_CIRCLEQ_INIT_ENTRY(new_observer, list_entry); + new_observer->observer = observer; + new_observer->notification = notification; + new_observer->callback = callback; + new_observer->data = data; + return new_observer; +} + +static void free_observer(observer_t *observer) +{ + DWC_FREE(observer); +} + +static notifier_t *alloc_notifier(void *object) +{ + notifier_t *notifier; + + if (!object) { + return NULL; + } + + notifier = DWC_ALLOC(sizeof(notifier_t)); + DWC_CIRCLEQ_INIT(¬ifier->observers); + DWC_CIRCLEQ_INIT_ENTRY(notifier, list_entry); + + notifier->object = object; + return notifier; +} + +static void free_notifier(notifier_t *notifier) +{ + observer_t *observer; + DWC_CIRCLEQ_FOREACH(observer, ¬ifier->observers, list_entry) { + free_observer(observer); + } + DWC_FREE(notifier); +} + +static notifier_t *find_notifier(void *object) +{ + notifier_t *notifier; + if (!object) { + return NULL; + } + DWC_ASSERT(manager, "Notification manager not found"); + DWC_CIRCLEQ_FOREACH(notifier, &manager->notifiers, list_entry) { + if (notifier->object == object) { + return notifier; + } + } + return NULL; +} + +void dwc_alloc_notification_manager(void) +{ + create_manager(); +} + +void dwc_free_notification_manager(void) +{ + free_manager(); +} + +dwc_notifier_t *dwc_register_notifier(void *object) +{ + notifier_t *notifier = find_notifier(object); + DWC_ASSERT(manager, "Notification manager not found"); + if (notifier) { + DWC_ERROR("Notifier %p is already registered", object); + return NULL; + } + + notifier = alloc_notifier(object); + DWC_CIRCLEQ_INSERT_TAIL(&manager->notifiers, notifier, list_entry); + + + DWC_INFO("Notifier %p registered", object); + dump_manager(); + + return notifier; +} + +void dwc_unregister_notifier(dwc_notifier_t *notifier) +{ + DWC_ASSERT(manager, "Notification manager not found"); + if (!DWC_CIRCLEQ_EMPTY(¬ifier->observers)) { + observer_t *o; + DWC_ERROR("Notifier %p has active observers when removing", notifier->object); + DWC_CIRCLEQ_FOREACH(o, ¬ifier->observers, list_entry) { + DWC_DEBUG(" %p watching %s", o->observer, o->notification); + } + DWC_ASSERT(DWC_CIRCLEQ_EMPTY(¬ifier->observers), "Notifier %p has active observers when removing", notifier); + } + + DWC_CIRCLEQ_REMOVE_INIT(&manager->notifiers, notifier, list_entry); + free_notifier(notifier); + + DWC_INFO("Notifier unregistered"); + dump_manager(); +} + +/* Add an observer to observe the notifier for a particular state, event, or notification. */ +int dwc_add_observer(void *observer, void *object, char *notification, dwc_notifier_callback_t callback, void *data) +{ + notifier_t *notifier = find_notifier(object); + observer_t *new_observer; + if (!notifier) { + DWC_ERROR("Notifier %p is not found when adding observer", object); + return -1; + } + + new_observer = alloc_observer(observer, notification, callback, data); + + DWC_CIRCLEQ_INSERT_TAIL(¬ifier->observers, new_observer, list_entry); + + DWC_INFO("Added observer %p to notifier %p observing notification %s, callback=%p, data=%p", + observer, object, notification, callback, data); + + dump_manager(); + return 0; +} + +int dwc_remove_observer(void *observer) +{ + notifier_t *n; + DWC_ASSERT(manager, "Notification manager not found"); + DWC_CIRCLEQ_FOREACH(n, &manager->notifiers, list_entry) { + observer_t *o; + observer_t *o2; + DWC_CIRCLEQ_FOREACH_SAFE(o, o2, &n->observers, list_entry) { + if (o->observer == observer) { + DWC_CIRCLEQ_REMOVE_INIT(&n->observers, o, list_entry); + DWC_INFO("Removing observer %p from notifier %p watching notification %s:", + o->observer, n->object, o->notification); + free_observer(o); + } + } + } + + dump_manager(); + return 0; +} + +typedef struct callback_data +{ + dwc_notifier_callback_t cb; + void *observer; + void *data; + void *object; + void *notification; + void *notification_data; +} cb_data_t; + +static void cb_task(void *data) +{ + cb_data_t *cb = (cb_data_t *)data; + cb->cb(cb->object, cb->notification, cb->observer, cb->notification_data, cb->data); + DWC_FREE(cb); +} + +void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data) +{ + observer_t *o; + DWC_ASSERT(manager, "Notification manager not found"); + DWC_CIRCLEQ_FOREACH(o, ¬ifier->observers, list_entry) { + int len = DWC_STRLEN(notification); + if (DWC_STRLEN(o->notification) != len) { + continue; + } + + if (DWC_STRNCMP(o->notification, notification, len) == 0) { + cb_data_t *cb_data = DWC_ALLOC(sizeof(cb_data_t)); + cb_data->cb = o->callback; + cb_data->observer = o->observer; + cb_data->data = o->data; + cb_data->object = notifier->object; + cb_data->notification = notification; + cb_data->notification_data = notification_data; + DWC_DEBUG("Observer found %p for notification %s", o->observer, notification); + DWC_WORKQ_SCHEDULE(manager->wq, cb_task, cb_data, + "Notify callback from %p for Notification %s, to observer %p", + cb_data->object, notification, cb_data->observer); + } + } +} + diff --git a/drivers/usb/host/dwc_common_port/dwc_notifier.h b/drivers/usb/host/dwc_common_port/dwc_notifier.h new file mode 100644 index 000000000000..a1388d17d156 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/dwc_notifier.h @@ -0,0 +1,112 @@ + +#ifndef __DWC_NOTIFIER_H__ +#define __DWC_NOTIFIER_H__ + +#include "dwc_os.h" + +/** @file + * + * A simple implementation of the Observer pattern. Any "module" can + * register as an observer or notifier. The notion of "module" is abstract and + * can mean anything used to identify either an observer or notifier. Usually + * it will be a pointer to a data structure which contains some state, ie an + * object. + * + * Before any notifiers can be added, the global notification manager must be + * brought up with dwc_alloc_notification_manager(). + * dwc_free_notification_manager() will bring it down and free all resources. + * These would typically be called upon module load and unload. The + * notification manager is a single global instance that handles all registered + * observable modules and observers so this should be done only once. + * + * A module can be observable by using Notifications to publicize some general + * information about it's state or operation. It does not care who listens, or + * even if anyone listens, or what they do with the information. The observable + * modules do not need to know any information about it's observers or their + * interface, or their state or data. + * + * Any module can register to emit Notifications. It should publish a list of + * notifications that it can emit and their behavior, such as when they will get + * triggered, and what information will be provided to the observer. Then it + * should register itself as an observable module. See dwc_register_notifier(). + * + * Any module can observe any observable, registered module, provided it has a + * handle to the other module and knows what notifications to observe. See + * dwc_add_observer(). + * + * A function of type dwc_notifier_callback_t is called whenever a notification + * is triggered with one or more observers observing it. This function is + * called in it's own process so it may sleep or block if needed. It is + * guaranteed to be called sometime after the notification has occurred and will + * be called once per each time the notification is triggered. It will NOT be + * called in the same process context used to trigger the notification. + * + * @section Limitiations + * + * Keep in mind that Notifications that can be triggered in rapid sucession may + * schedule too many processes too handle. Be aware of this limitation when + * designing to use notifications, and only add notifications for appropriate + * observable information. + * + * Also Notification callbacks are not synchronous. If you need to synchronize + * the behavior between module/observer you must use other means. And perhaps + * that will mean Notifications are not the proper solution. + */ + +struct dwc_notifier; +typedef struct dwc_notifier dwc_notifier_t; + +/** The callback function must be of this type. + * + * @param object This is the object that is being observed. + * @param notification This is the notification that was triggered. + * @param observer This is the observer + * @param notification_data This is notification-specific data that the notifier + * has included in this notification. The value of this should be published in + * the documentation of the observable module with the notifications. + * @param user_data This is any custom data that the observer provided when + * adding itself as an observer to the notification. */ +typedef void (*dwc_notifier_callback_t)(void *object, char *notification, void *observer, void *notification_data, void *user_data); + +/** Brings up the notification manager. */ +extern void dwc_alloc_notification_manager(void); +/** Brings down the notification manager. */ +extern void dwc_free_notification_manager(void); + +/** This function register an observable module. A dwc_notifier_t object is + * returned to the observable module. This is an opaque object that is used by + * the observable module to trigger notifications. This object should only be + * accessible to functions that are authorized to trigger notifications for this + * module. Observers do not need this object. */ +extern dwc_notifier_t *dwc_register_notifier(void *object); + +/** This function unregister an observable module. All observers have to be + * removed prior to unregistration. */ +extern void dwc_unregister_notifier(dwc_notifier_t *notifier); + +/** Add a module as an observer to the observable module. The observable module + * needs to have previously registered with the notification manager. + * + * @param observer The observer module + * @param object The module to observe + * @param notification The notification to observe + * @param callback The callback function to call + * @param user_data Any additional user data to pass into the callback function */ +extern int dwc_add_observer(void *observer, void *object, char *notification, dwc_notifier_callback_t callback, void *user_data); + +/** Removes the specified observer from all notifications that it is currently + * observing. */ +extern int dwc_remove_observer(void *observer); + +/** This function triggers a Notification. It should be called by the + * observable module, or any module or library which the observable module + * allows to trigger notification on it's behalf. Such as the dwc_cc_t. + * + * dwc_notify is a non-blocking function. Callbacks are scheduled called in + * their own process context for each trigger. Callbacks can be blocking. + * dwc_notify can be called from interrupt context if needed. + * + */ +void dwc_notify(dwc_notifier_t *notifier, char *notification, void *notification_data); + +#endif /* __DWC_NOTIFIER_H__ */ diff --git a/drivers/usb/host/dwc_common_port/dwc_os.h b/drivers/usb/host/dwc_common_port/dwc_os.h new file mode 100644 index 000000000000..8d3801408335 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/dwc_os.h @@ -0,0 +1,924 @@ +/* ========================================================================= + * $File: //dwh/usb_iip/dev/software/dwc_common_port/dwc_os.h $ + * $Revision: #2 $ + * $Date: 2009/04/02 $ + * $Change: 1224130 $ + * + * Synopsys Portability Library Software and documentation + * (hereinafter, "Software") is an Unsupported proprietary work of + * Synopsys, Inc. unless otherwise expressly agreed to in writing + * between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product + * under any End User Software License Agreement or Agreement for + * Licensed Product with Synopsys or any supplement thereto. You are + * permitted to use and redistribute this Software in source and binary + * forms, with or without modification, provided that redistributions + * of source code must retain this notice. You may not view, use, + * disclose, copy or distribute this file or any information contained + * herein except pursuant to this license grant from Synopsys. If you + * do not agree with this notice, including the disclaimer below, then + * you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" + * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL + * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================= */ +#ifndef _DWC_OS_H_ +#define _DWC_OS_H_ + +/** @file + * + * DWC portability library, low level os-wrapper functions + * + */ + +/* These basic types need to be defined by some OS header file or custom header + * file for your specific target architecture. + * + * uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t + * + * Any custom or alternate header file must be added and enabled here. + */ + +#ifdef DWC_LINUX +# include +# ifdef CONFIG_DEBUG_MUTEXES +# include +# endif +#else +# include +#endif + + +/** @name Primitive Types and Values */ + +/** We define a boolean type for consistency. Can be either YES or NO */ +typedef uint8_t dwc_bool_t; +#define YES 1 +#define NO 0 + +/** @todo make them positive and return the negative error code */ +/** @name Error Codes */ +#define DWC_E_INVALID 1001 +#define DWC_E_NO_MEMORY 1002 +#define DWC_E_NO_DEVICE 1003 +#define DWC_E_NOT_SUPPORTED 1004 +#define DWC_E_TIMEOUT 1005 +#define DWC_E_BUSY 1006 +#define DWC_E_AGAIN 1007 +#define DWC_E_RESTART 1008 +#define DWC_E_ABORT 1009 +#define DWC_E_SHUTDOWN 1010 +#define DWC_E_NO_DATA 1011 +#define DWC_E_DISCONNECT 2000 +#define DWC_E_UNKNOWN 3000 +#define DWC_E_NO_STREAM_RES 4001 +#define DWC_E_COMMUNICATION 4002 +#define DWC_E_OVERFLOW 4003 +#define DWC_E_PROTOCOL 4004 +#define DWC_E_IN_PROGRESS 4005 +#define DWC_E_PIPE 4006 +#define DWC_E_IO 4007 +#define DWC_E_NO_SPACE 4008 + +/** @name Tracing/Logging Functions + * + * These function provide the capability to add tracing, debugging, and error + * messages, as well exceptions as assertions. The WUDEV uses these + * extensively. These could be logged to the main console, the serial port, an + * internal buffer, etc. These functions could also be no-op if they are too + * expensive on your system. By default undefining the DEBUG macro already + * no-ops some of these functions. */ + +#include + +/** Returns non-zero if in interrupt context. */ +extern dwc_bool_t DWC_IN_IRQ(void); +#define dwc_in_irq DWC_IN_IRQ + +/** Returns "IRQ" if DWC_IN_IRQ is true. */ +static inline char *dwc_irq(void) { + return DWC_IN_IRQ() ? "IRQ" : ""; +} + +/** + * A vprintf() clone. Just call vprintf if you've got it. + */ +extern void DWC_VPRINTF(char *format, va_list args); +#define dwc_vprintf DWC_VPRINTF + +/** + * A vsnprintf() clone. Just call vprintf if you've got it. + */ +extern int DWC_VSNPRINTF(char *str, int size, char *format, va_list args); +#define dwc_vsnprintf DWC_VSNPRINTF + +/** + * printf() clone. Just call printf if you've go it. + */ +extern void DWC_PRINTF(char *format, ...) +/* This provides compiler level static checking of the parameters if you're + * using GCC. */ +#ifdef __GNUC__ + __attribute__ ((format(printf, 1, 2))); +#else + ; +#endif +#define dwc_printf DWC_PRINTF + +/** + * sprintf() clone. Just call sprintf if you've got it. + */ +extern int DWC_SPRINTF(char *string, char *format, ...) +#ifdef __GNUC__ + __attribute__ ((format(printf, 2, 3))); +#else + ; +#endif +#define dwc_sprintf DWC_SPRINTF + +/** + * snprintf() clone. Just call snprintf if you've got it. + */ +extern int DWC_SNPRINTF(char *string, int size, char *format, ...) +#ifdef __GNUC__ + __attribute__ ((format(printf, 3, 4))); +#else + ; +#endif +#define dwc_snprintf DWC_SNPRINTF + +/** + * Prints a WARNING message. On systems that don't differentiate between + * warnings and regular log messages, just print it. Indicates that something + * may be wrong with the driver. Works like printf(). + * + * Use the DWC_WARN macro to call this function. + */ +extern void __DWC_WARN(char *format, ...) +#ifdef __GNUC__ + __attribute__ ((format(printf, 1, 2))); +#else + ; +#endif + +/** + * Prints an error message. On systems that don't differentiate between errors + * and regular log messages, just print it. Indicates that something went wrong + * with the driver, but it can be recovered from. Works like printf(). + * + * Use the DWC_ERROR macro to call this function. + */ +extern void __DWC_ERROR(char *format, ...) +#ifdef __GNUC__ + __attribute__ ((format(printf, 1, 2))); +#else + ; +#endif + +/** + * Prints an exception error message and takes some user-defined action such as + * print out a backtrace or trigger a breakpoint. Indicates that something went + * abnormally wrong with the driver such as programmer error, or other + * exceptional condition. It should not be ignored so even on systems without + * printing capability, some action should be taken to notify the developer of + * it. Works like printf(). + */ +extern void DWC_EXCEPTION(char *format, ...) +#ifdef __GNUC__ + __attribute__ ((format(printf, 1, 2))); +#else + ; +#endif +#define dwc_exception DWC_EXCEPTION + +#ifdef DEBUG +/** + * Prints out a debug message. Used for logging/trace messages. + * + * Use the DWC_DEBUG macro to call this function + */ +extern void __DWC_DEBUG(char *format, ...) +#ifdef __GNUC__ + __attribute__ ((format(printf, 1, 2))); +#else + ; +#endif +#else +#define __DWC_DEBUG printk +#endif + +/** + * Prints out a Debug message. + */ +#define DWC_DEBUG(_format, _args...) __DWC_DEBUG("DEBUG:%s:%s: " _format "\n", __func__, dwc_irq(), ## _args) +#define dwc_debug DWC_DEBUG +/** + * Prints out an informative message. + */ +#define DWC_INFO(_format, _args...) DWC_PRINTF("INFO:%s: " _format "\n", dwc_irq(), ## _args) +#define dwc_info DWC_INFO +/** + * Prints out a warning message. + */ +#define DWC_WARN(_format, _args...) __DWC_WARN("WARN:%s:%s:%d: " _format "\n", dwc_irq(), __func__, __LINE__, ## _args) +#define dwc_warn DWC_WARN +/** + * Prints out an error message. + */ +#define DWC_ERROR(_format, _args...) __DWC_ERROR("ERROR:%s:%s:%d: " _format "\n", dwc_irq(), __func__, __LINE__, ## _args) +#define dwc_error DWC_ERROR + +#define DWC_PROTO_ERROR(_format, _args...) __DWC_WARN("ERROR:%s:%s:%d: " _format "\n", dwc_irq(), __func__, __LINE__, ## _args) +#define dwc_proto_error DWC_PROTO_ERROR + +#ifdef DEBUG +/** Prints out a exception error message if the _expr expression fails. Disabled + * if DEBUG is not enabled. */ +#define DWC_ASSERT(_expr, _format, _args...) if (!(_expr)) { DWC_EXCEPTION("%s:%s:%d: " _format "\n", dwc_irq(), __FILE__, __LINE__, ## _args); } +#else +#define DWC_ASSERT(_x...) +#endif +#define dwc_assert DWC_ASSERT + +/** @name Byter Ordering + * The following functions are for conversions between processor's byte ordering + * and specific ordering you want. + */ + +/** Converts 32 bit data in CPU byte ordering to little endian. */ +extern uint32_t DWC_CPU_TO_LE32(void *p); +#define dwc_cpu_to_le32 DWC_CPU_TO_LE32 +/** Converts 32 bit data in CPU byte orderint to big endian. */ +extern uint32_t DWC_CPU_TO_BE32(void *p); +#define dwc_cpu_to_be32 DWC_CPU_TO_BE32 + +/** Converts 32 bit little endian data to CPU byte ordering. */ +extern uint32_t DWC_LE32_TO_CPU(void *p); +#define dwc_le32_to_cpu DWC_LE32_TO_CPU +/** Converts 32 bit big endian data to CPU byte ordering. */ +extern uint32_t DWC_BE32_TO_CPU(void *p); +#define dwc_be32_to_cpu DWC_BE32_TO_CPU + +/** Converts 16 bit data in CPU byte ordering to little endian. */ +extern uint16_t DWC_CPU_TO_LE16(void *p); +#define dwc_cpu_to_le16 DWC_CPU_TO_LE16 +/** Converts 16 bit data in CPU byte orderint to big endian. */ +extern uint16_t DWC_CPU_TO_BE16(void *p); +#define dwc_cpu_to_be16 DWC_CPU_TO_BE16 + +/** Converts 16 bit little endian data to CPU byte ordering. */ +extern uint16_t DWC_LE16_TO_CPU(void *p); +#define dwc_le16_to_cpu DWC_LE16_TO_CPU +/** Converts 16 bit bi endian data to CPU byte ordering. */ +extern uint16_t DWC_BE16_TO_CPU(void *p); +#define dwc_be16_to_cpu DWC_BE16_TO_CPU + +/** @name Register Read/Write + * + * The following five functions should be implemented to read/write registers of + * 32-bit and 64-bit sizes. All modules use this to read/write register values. + * The reg value is a pointer to the register calculated from the void *base + * variable passed into the driver when it is started. */ + +/** Reads the content of a 32-bit register. */ +extern uint32_t DWC_READ_REG32(uint32_t volatile *reg); +#define dwc_read_reg32 DWC_READ_REG32 +/** Reads the content of a 64-bit register. */ +extern uint64_t DWC_READ_REG64(uint64_t volatile *reg); +#define dwc_read_reg64 DWC_READ_REG64 +/** Writes to a 32-bit register. */ +extern void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value); +#define dwc_write_reg32 DWC_WRITE_REG32 +/** Writes to a 64-bit register. */ +extern void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value); +#define dwc_write_reg64 DWC_WRITE_REG64 +/** + * Modify bit values in a register. Using the + * algorithm: (reg_contents & ~clear_mask) | set_mask. + */ +extern void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask); +#define dwc_modify_reg32 DWC_MODIFY_REG32 + +/** @cond */ + +/** @name Some convenience MACROS used internally. Define DEBUG_REGS to log the + * register writes. */ + +#ifdef DEBUG_REGS + +#define dwc_define_read_write_reg_n(_reg,_container_type) \ +static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \ + return DWC_READ_REG32(&container->regs->_reg[num]); \ +} \ +static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \ + DWC_DEBUG("WRITING %8s[%d]: %p: %08x", #_reg, num, &(((uint32_t*)container->regs->_reg)[num]), data); \ + DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \ +} + +#define dwc_define_read_write_reg(_reg,_container_type) \ +static inline uint32_t dwc_read_##_reg(_container_type *container) { \ + return DWC_READ_REG32(&container->regs->_reg); \ +} \ +static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \ + DWC_DEBUG("WRITING %11s: %p: %08x", #_reg, &container->regs->_reg, data); \ + DWC_WRITE_REG32(&container->regs->_reg, data); \ +} + +#else + +#define dwc_define_read_write_reg_n(_reg,_container_type) \ +static inline uint32_t dwc_read_##_reg##_n(_container_type *container, int num) { \ + return DWC_READ_REG32(&container->regs->_reg[num]); \ +} \ +static inline void dwc_write_##_reg##_n(_container_type *container, int num, uint32_t data) { \ + DWC_WRITE_REG32(&(((uint32_t*)container->regs->_reg)[num]), data); \ +} + +#define dwc_define_read_write_reg(_reg,_container_type) \ +static inline uint32_t dwc_read_##_reg(_container_type *container) { \ + return DWC_READ_REG32(&container->regs->_reg); \ +} \ +static inline void dwc_write_##_reg(_container_type *container, uint32_t data) { \ + DWC_WRITE_REG32(&container->regs->_reg, data); \ +} + +#endif + +/** @endcond */ + + +/** @name Crypto Functions + * + * These are the low-level cryptographic functions used by the driver. */ + +/** Perform AES CBC */ +extern int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out); +#define dwc_aes_cbc DWC_AES_CBC +/** Fill the provided buffer with random bytes. These should be cryptographic grade random numbers. */ +extern void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length); +#define dwc_random_bytes DWC_RANDOM_BYTES +/** Perform the SHA-256 hash function */ +extern int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out); +#define dwc_sha256 DWC_SHA256 +/** Calculated the HMAC-SHA256 */ +extern int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t *out); +#define dwc_hmac_sha256 DWC_HMAC_SHA256 + + +/** @name Memory Allocation + * + * These function provide access to memory allocation. There are only 2 DMA + * functions and 3 Regular memory functions that need to be implemented. None + * of the memory debugging routines need to be implemented. The allocation + * routines all ZERO the contents of the memory. + * + * Defining DEBUG_MEMORY turns on memory debugging and statistic gathering. + * This checks for memory leaks, keeping track of alloc/free pairs. It also + * keeps track of how much memory the driver is using at any given time. */ + +#define DWC_PAGE_SIZE 4096 +#define DWC_PAGE_OFFSET(addr) (((uint32_t)addr) & 0xfff) +#define DWC_PAGE_ALIGNED(addr) ((((uint32_t)addr) & 0xfff) == 0) + +#define DWC_INVALID_DMA_ADDR 0x0 + +typedef uint32_t dwc_dma_t; + +/** @todo these functions will be added in the future */ +#if 0 +/** + * Creates a DMA pool from which you can allocate DMA buffers. Buffers + * allocated from this pool will be guaranteed to meet the size, alignment, and + * boundary requirements specified. + * + * @param[in] size Specifies the size of the buffers that will be allocated from + * this pool. + * @param[in] align Specifies the byte alignment requirements of the buffers + * allocated from this pool. Must be a power of 2. + * @param[in] boundary Specifies the N-byte boundary that buffers allocated from + * this pool must not cross. + * + * @returns A pointer to an internal opaque structure which is not to be + * accessed outside of these library functions. Use this handle to specify + * which pools to allocate/free DMA buffers from and also to destroy the pool, + * when you are done with it. + */ +extern dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size, uint32_t align, uint32_t boundary); +/** + * Destroy a DMA pool. All buffers allocated from that pool must be freed first. + */ +extern void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool); +/** + * Allocate a buffer from the specified DMA pool and zeros its contents. + */ +extern void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr); +/** + * Free a previously allocated buffer from the DMA pool. + */ +extern void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr); +#endif + + +/** Allocates a DMA capable buffer and zeroes its contents. */ +extern void *__DWC_DMA_ALLOC(uint32_t size, dwc_dma_t *dma_addr); + +/** Allocates a DMA capable buffer and zeroes its contents in atomic contest */ +extern void *__DWC_DMA_ALLOC_ATOMIC(uint32_t size, dwc_dma_t *dma_addr); + +/** Frees a previosly allocated buffer. */ +extern void __DWC_DMA_FREE(uint32_t size, void *virt_addr, dwc_dma_t dma_addr); + +/** Allocates a block of memory and zeroes its contents. */ +extern void *__DWC_ALLOC(uint32_t size); + +/** Allocates a block of memory and zeroes its contents, in an atomic manner + * which can be used inside interrupt context. The size should be sufficiently + * small, a few KB at most, such that failures are not likely to occur. Can just call + * __DWC_ALLOC if it is atomic. */ +extern void *__DWC_ALLOC_ATOMIC(uint32_t size); + +/** Frees a previously allocated buffer. */ +extern void __DWC_FREE(void *addr); + +#ifndef DEBUG_MEMORY + +#define DWC_ALLOC(_size_) __DWC_ALLOC(_size_) +#define DWC_ALLOC_ATOMIC(_size_) __DWC_ALLOC_ATOMIC(_size_) +#define DWC_FREE(_addr_) __DWC_FREE(_addr_) +#define DWC_DMA_ALLOC(_size_,_dma_) __DWC_DMA_ALLOC(_size_,_dma_) +#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) __DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) +#define DWC_DMA_FREE(_size_,_virt_,_dma_) __DWC_DMA_FREE(_size_,_virt_,_dma_) + +#else + +extern void *dwc_alloc_debug(uint32_t size, char const *func, int line); +extern void *dwc_alloc_atomic_debug(uint32_t size, char const *func, int line); +extern void dwc_free_debug(void *addr, char const *func, int line); +extern void *dwc_dma_alloc_debug(uint32_t size, dwc_dma_t *dma_addr, char const *func, int line); +extern void *dwc_dma_alloc_atomic_debug(uint32_t size, dwc_dma_t *dma_addr, char const *func, int line); +extern void dwc_dma_free_debug(uint32_t size, void *virt_addr, dwc_dma_t dma_addr, char const *func, int line); + +extern void dwc_memory_debug_start(void); +extern void dwc_memory_debug_stop(void); +extern void dwc_memory_debug_report(void); + +#define DWC_ALLOC(_size_) (dwc_alloc_debug(_size_, __func__, __LINE__)) +#define DWC_ALLOC_ATOMIC(_size_) (dwc_alloc_atomic_debug(_size_, __func__, __LINE__)) +#define DWC_FREE(_addr_) (dwc_free_debug(_addr_, __func__, __LINE__)) +#define DWC_DMA_ALLOC(_size_,_dma_) dwc_dma_alloc_debug(_size_, _dma_, __func__, __LINE__) +#define DWC_DMA_ALLOC_ATOMIC(_size_,_dma_) dwc_dma_alloc_atomic_debug(_size_, _dma_, __func__, __LINE__) +#define DWC_DMA_FREE(_size_,_virt_,_dma_) dwc_dma_free_debug(_size_, _virt_, _dma_, __func__, __LINE__) + +#endif /* DEBUG_MEMORY */ + +#define dwc_alloc DWC_ALLOC +#define dwc_alloc_atomic DWC_ALLOC_ATOMIC +#define dwc_free DWC_FREE +#define dwc_dma_alloc DWC_DMA_ALLOC +#define dwc_dma_alloc_atomic DWC_DMA_ALLOC_ATOMIC +#define dwc_dma_free DWC_DMA_FREE + + +/** @name Memory and String Processing */ + +/** memset() clone */ +extern void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size); +#define dwc_memset DWC_MEMSET +/** memcpy() clone */ +extern void *DWC_MEMCPY(void *dest, void const *src, uint32_t size); +#define dwc_memcpy DWC_MEMCPY +/** memmove() clone */ +extern void *DWC_MEMMOVE(void *dest, void *src, uint32_t size); +#define dwc_memmove DWC_MEMMOVE +/** memcmp() clone */ +extern int DWC_MEMCMP(void *m1, void *m2, uint32_t size); +#define dwc_memcmp DWC_MEMCMP +/** strcmp() clone */ +extern int DWC_STRCMP(void *s1, void *s2); +#define dwc_strcmp DWC_STRCMP +/** strncmp() clone */ +extern int DWC_STRNCMP(void *s1, void *s2, uint32_t size); +#define dwc_strncmp DWC_STRNCMP +/** strlen() clone, for NULL terminated ASCII strings */ +extern int DWC_STRLEN(char const *str); +#define dwc_strlen DWC_STRLEN +/** strcpy() clone, for NULL terminated ASCII strings */ +extern char *DWC_STRCPY(char *to, const char *from); +#define dwc_strcpy DWC_STRCPY + +/** strdup() clone. If you wish to use memory allocation debugging, this + * implementation of strdup should use the DWC_* memory routines instead of + * calling a predefined strdup. Otherwise the memory allocated by this routine + * will not be seen by the debugging routines. */ +extern char *DWC_STRDUP(char const *str); +#define dwc_strdup DWC_STRDUP + +/** NOT an atoi() clone. Read the description carefully. Returns an integer + * converted from the string str in base 10 unless the string begins with a "0x" + * in which case it is base 16. String must be a NULL terminated sequence of + * ASCII characters and may optionally begin with whitespace, a + or -, and a + * "0x" prefix if base 16. The remaining characters must be valid digits for + * the number and end with a NULL character. If any invalid characters are + * encountered or it returns with a negative error code and the results of the + * conversion are undefined. On sucess it returns 0. Overflow conditions are + * undefined. An example implementation using atoi() can be referenced from the + * Linux implementation. */ +extern int DWC_ATOI(char *str, int32_t *value); +#define dwc_atoi DWC_ATOI +/** Same as above but for unsigned. */ +extern int DWC_ATOUI(char *str, uint32_t *value); +#define dwc_atoui DWC_ATOUI +/** This routine returns a UTF16LE unicode encoded string from a UTF8 string. */ +extern int DWC_UTF8_TO_UTF16LE(uint8_t const *utf8string, uint16_t *utf16string, unsigned len); +#define dwc_utf8_to_utf16le DWC_UTF8_TO_UTF16LE + +/** @name Wait queues + * + * Wait queues provide a means of synchronizing between threads or processes. A + * process can block on a waitq if some condition is not true, waiting for it to + * become true. When the waitq is triggered all waiting process will get + * unblocked and the condition will be check again. Waitqs should be triggered + * every time a condition can potentially change.*/ +struct dwc_waitq; +typedef struct dwc_waitq dwc_waitq_t; + +/** The type of waitq condition callback function. This is called every time + * condition is evaluated. */ +typedef int (*dwc_waitq_condition_t)(void *data); + +/** Allocate a waitq */ +extern dwc_waitq_t *DWC_WAITQ_ALLOC(void); +#define dwc_waitq_alloc DWC_WAITQ_ALLOC +/** Free a waitq */ +extern void DWC_WAITQ_FREE(dwc_waitq_t *wq); +#define dwc_waitq_free DWC_WAITQ_FREE + +/** Check the condition and if it is false, block on the waitq. When unblocked, check the + * condition again. The function returns when the condition becomes true. The return value + * is 0 on condition true, DWC_WAITQ_ABORTED on abort or killed, or DWC_WAITQ_UNKNOWN on error. */ +extern int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t condition, void *data); +#define dwc_waitq_wait DWC_WAITQ_WAIT; +/** Check the condition and if it is false, block on the waitq. When unblocked, + * check the condition again. The function returns when the condition become + * true or the timeout has passed. The return value is 0 on condition true or + * DWC_TIMED_OUT on timeout, or DWC_WAITQ_ABORTED, or DWC_WAITQ_UNKNOWN on + * error. */ +extern int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t condition, void *data, int32_t msecs); +#define dwc_waitq_wait_timeout DWC_WAITQ_WAIT_TIMEOUT +/** Trigger a waitq, unblocking all processes. This should be called whenever a condition + * has potentially changed. */ +extern void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq); +#define dwc_waitq_trigger DWC_WAITQ_TRIGGER +/** Unblock all processes waiting on the waitq with an ABORTED result. */ +extern void DWC_WAITQ_ABORT(dwc_waitq_t *wq); +#define dwc_waitq_abort DWC_WAITQ_ABORT + +/** @name Threads + * + * A thread must be explicitly stopped. It must check DWC_THREAD_SHOULD_STOP + * whenever it is woken up, and then return. The DWC_THREAD_STOP function + * returns the value from the thread. + */ + +struct dwc_thread; +typedef struct dwc_thread dwc_thread_t; + +/** The thread function */ +typedef int (*dwc_thread_function_t)(void *data); + +/** Create a thread and start it running the thread_function. Returns a handle + * to the thread */ +extern dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t thread_function, char *name, void *data); +#define dwc_thread_run DWC_THREAD_RUN +/** Stops a thread. Return the value returned by the thread. Or will return + * DWC_ABORT if the thread never started. */ +extern int DWC_THREAD_STOP(dwc_thread_t *thread); +#define dwc_thread_stop DWC_THREAD_STOP +/** Signifies to the thread that it must stop. */ +extern dwc_bool_t DWC_THREAD_SHOULD_STOP(void); +#define dwc_thread_should_stop DWC_THREAD_SHOULD_STOP + +/** @name Work queues + * + * Workqs are used to queue a callback function to be called at some later time, + * in another thread. */ +struct dwc_workq; +typedef struct dwc_workq dwc_workq_t; + +/** The type of the callback function to be called. */ +typedef void (*dwc_work_callback_t)(void *data); + +/** Allocate a workq */ +extern dwc_workq_t *DWC_WORKQ_ALLOC(char *name); +#define dwc_workq_alloc DWC_WORKQ_ALLOC +/** Free a workq. All work must be completed before being freed. */ +extern void DWC_WORKQ_FREE(dwc_workq_t *workq); +#define dwc_workq_free DWC_WORKQ_FREE +/** Schedule a callback on the workq, passing in data. The function will be + * scheduled at some later time. */ +extern void DWC_WORKQ_SCHEDULE(dwc_workq_t *workq, dwc_work_callback_t work_cb, void *data, char *format, ...) +#ifdef __GNUC__ + __attribute__ ((format(printf, 4, 5))); +#else + ; +#endif +#define dwc_workq_schedule DWC_WORKQ_SCHEDULE + +/** Schedule a callback on the workq, that will be called until at least + * given number miliseconds have passed. */ +extern void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *workq, dwc_work_callback_t work_cb, void *data, uint32_t time, char *format, ...) +#ifdef __GNUC__ + __attribute__ ((format(printf, 5, 6))); +#else + ; +#endif +#define dwc_workq_schedule_delayed DWC_WORKQ_SCHEDULE_DELAYED + +/** The number of processes in the workq */ +extern int DWC_WORKQ_PENDING(dwc_workq_t *workq); +#define dwc_workq_pending DWC_WORKQ_PENDING +/** Blocks until all the work in the workq is complete or timed out. Returns < + * 0 on timeout. */ +extern int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout); +#define dwc_workq_wait_work_done DWC_WORKQ_WAIT_WORK_DONE + + +/** @name Tasklets + * + */ +struct dwc_tasklet; +typedef struct dwc_tasklet dwc_tasklet_t; + +typedef void (*dwc_tasklet_callback_t)(void *data); + +extern dwc_tasklet_t *DWC_TASK_ALLOC(dwc_tasklet_callback_t cb, void *data); +#define dwc_task_alloc DWC_TASK_ALLOC +extern void DWC_TASK_FREE(dwc_tasklet_t *t); +#define dwc_task_free DWC_TASK_FREE +extern void DWC_TASK_SCHEDULE(dwc_tasklet_t *task); +#define dwc_task_schedule DWC_TASK_SCHEDULE + + +/** @name Timer + * + * Callbacks must be small and atomic. + */ +struct dwc_timer; +typedef struct dwc_timer dwc_timer_t; + +typedef void (*dwc_timer_callback_t)(void *data); + +extern dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data); +#define dwc_timer_alloc DWC_TIMER_ALLOC +extern void DWC_TIMER_FREE(dwc_timer_t *timer); +#define dwc_timer_free DWC_TIMER_FREE + +/** Schedules the timer to run at time ms from now. And will repeat at every + * repeat_interval msec therafter + * + * Modifies a timer that is still awaiting execution to a new expiration time. + * The mod_time is added to the old time. */ +extern void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time); +#define dwc_timer_schedule DWC_TIMER_SCHEDULE + +/** Disables the timer from execution. */ +extern void DWC_TIMER_CANCEL(dwc_timer_t *timer); +#define dwc_timer_cancel DWC_TIMER_CANCEL + + + +/** @name Spinlocks + * + * These locks are used when the work between the lock/unlock is atomic and + * short. Interrupts are also disabled during the lock/unlock and thus they are + * suitable to lock between interrupt/non-interrupt context. They also lock + * between processes if you have multiple CPUs or Preemption. If you don't have + * multiple CPUS or Preemption, then the you can simply implement the + * DWC_SPINLOCK and DWC_SPINUNLOCK to disable and enable interrupts. Because + * the work between the lock/unlock is atomic, the process context will never + * change, and so you never have to lock between processes. */ + +struct dwc_spinlock; +typedef struct dwc_spinlock dwc_spinlock_t; + +/** Returns an initialized lock variable. This function should allocate and + * initialize the OS-specific data structure used for locking. This data + * structure is to be used for the DWC_LOCK and DWC_UNLOCK functions and should + * be freed by the DWC_FREE_LOCK when it is no longer used. */ +extern dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void); +#define dwc_spinlock_alloc DWC_SPINLOCK_ALLOC + +/** Frees an initialized lock variable. */ +extern void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock); +#define dwc_spinlock_free DWC_SPINLOCK_FREE + +/** Disables interrupts and blocks until it acquires the lock. + * + * @param lock Pointer to the spinlock. + * @param flags Unsigned long for irq flags storage. + */ +extern void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, uint64_t *flags); +#define dwc_spinlock_irqsave DWC_SPINLOCK_IRQSAVE + +/** Re-enables the interrupt and releases the lock. + * + * @param lock Pointer to the spinlock. + * @param flags Unsigned long for irq flags storage. Must be the same as was + * passed into DWC_LOCK. + */ +extern void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, uint64_t flags); +#define dwc_spinunlock_irqrestore DWC_SPINUNLOCK_IRQRESTORE + +/** Blocks until it acquires the lock. + * + * @param lock Pointer to the spinlock. + */ +extern void DWC_SPINLOCK(dwc_spinlock_t *lock); +#define dwc_spinlock DWC_SPINLOCK + +/** Releases the lock. + * + * @param lock Pointer to the spinlock. + */ +extern void DWC_SPINUNLOCK(dwc_spinlock_t *lock); +#define dwc_spinunlock DWC_SPINUNLOCK + +/** @name Mutexes + * + * Unlike spinlocks Mutexes lock only between processes and the work between the + * lock/unlock CAN block, therefore it CANNOT be called from interrupt context. + */ + +struct dwc_mutex; +typedef struct dwc_mutex dwc_mutex_t; + + +/* For Linux Mutex Debugging make it inline because the debugging routines use + * the symbol to determine recursive locking. This makes it falsely think + * recursive locking occurs. */ +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)) +#define DWC_MUTEX_ALLOC_LINUX_DEBUG(__mutexp) ({ \ + __mutexp = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex)); \ + mutex_init((struct mutex *)__mutexp); \ +}) +#endif +extern dwc_mutex_t *DWC_MUTEX_ALLOC(void); +#define dwc_mutex_alloc DWC_MUTEX_ALLOC + +/* For memory leak debugging when using Linux Mutex Debugging */ +#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)) +#define DWC_MUTEX_FREE(__mutexp) do { \ + mutex_destroy((struct mutex *)__mutexp); \ + DWC_FREE(__mutexp); \ +} while(0) +#else +extern void DWC_MUTEX_FREE(dwc_mutex_t *mutex); +#define dwc_mutex_free DWC_MUTEX_FREE +#endif + +extern void DWC_MUTEX_LOCK(dwc_mutex_t *mutex); +#define dwc_mutex_lock DWC_MUTEX_LOCK +/** Non-blocking lock returns 1 on successful lock. */ +extern int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex); +#define dwc_mutex_trylock DWC_MUTEX_TRYLOCK +extern void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex); +#define dwc_mutex_unlock DWC_MUTEX_UNLOCK + + + + +/** @name Time */ + +/** Microsecond delay. + * + * @param usecs Microseconds to delay. + */ +extern void DWC_UDELAY(uint32_t usecs); +#define dwc_udelay DWC_UDELAY + +/** Millisecond delay. + * + * @param msecs Milliseconds to delay. + */ +extern void DWC_MDELAY(uint32_t msecs); +#define dwc_mdelay DWC_MDELAY + +/** Non-busy waiting. + * Sleeps for specified number of milliseconds. + * + * @param msecs Milliseconds to sleep. + */ +extern void DWC_MSLEEP(uint32_t msecs); +#define dwc_msleep DWC_MSLEEP + +extern uint32_t DWC_TIME(void); +#define dwc_time DWC_TIME + +#endif // _DWC_OS_H_ + + + + +/** @mainpage DWC Portability and Common Library + * + * This is the documentation for the DWC Portability and Common Library. + * + * @section intro Introduction + * + * The DWC Portability library consists of wrapper calls and data structures to + * all low-level functions which are typically provided by the OS. The WUDEV + * driver uses only these functions. In order to port the WUDEV driver, only + * the functions in this library need to be re-implemented, with the same + * behavior as documented here. + * + * The Common library consists of higher level functions, which rely only on + * calling the functions from the DWC Portability library. These common + * routines are shared across modules. Some of the common libraries need to be + * used directly by the driver programmer when porting WUDEV. Such as the + * parameter and notification libraries. + * + * @section low Portability Library OS Wrapper Functions + * + * Any function starting with DWC and in all CAPS is a low-level OS-wrapper that + * needs to be implemented when porting, for example DWC_MUTEX_ALLOC(). All of + * these functions are included in the dwc_os.h file. + * + * There are many functions here covering a wide array of OS services. Please + * see dwc_os.h for details, and implementation notes for each function. + * + * @section common Common Library Functions + * + * Any function starting with dwc and in all lowercase is a common library + * routine. These functions have a portable implementation and do not need to + * be reimplemented when porting. The common routines can be used by any + * driver, and some must be used by the end user to control the drivers. For + * example, you must use the Parameter common library in order to set the + * parameters in the WUDEV module. + * + * The common libraries consist of the following: + * + * - Connection Contexts - Used internally and can be used by end-user. See dwc_cc.h + * - Parameters - Used internally and can be used by end-user. See dwc_params.h + * - Notifications - Used internally and can be used by end-user. See dwc_notifier.h + * - Lists - Used internally and can be used by end-user. See dwc_list.h + * - Memory Debugging - Used internally and can be used by end-user. See dwc_os.h + * - Modpow - Used internally only. See dwc_modpow.h + * - DH - Used internally only. See dwc_dh.h + * - Crypto - Used internally only. See dwc_crypto.h + * + * + * @section prereq Prerequistes For dwc_os.h + * @subsection types Data Types + * + * The dwc_os.h file assumes that several low-level data types are pre defined for the + * compilation environment. These data types are: + * + * - uint8_t - unsigned 8-bit data type + * - int8_t - signed 8-bit data type + * - uint16_t - unsigned 16-bit data type + * - int16_t - signed 16-bit data type + * - uint32_t - unsigned 32-bit data type + * - int32_t - signed 32-bit data type + * - uint64_t - unsigned 64-bit data type + * - int64_t - signed 64-bit data type + * + * Ensure that these are defined before using dwc_os.h. The easiest way to do + * that is to modify the top of the file to include the appropriate header. + * This is already done for the Linux environment. If the DWC_LINUX macro is + * defined, the correct header will be added. A standard header is + * also used for environments where standard C headers are available. + * + * @subsection stdarg Variable Arguments + * + * Variable arguments are provided by a standard C header . it is + * available in Both the Linux and ANSI C enviornment. An equivalent must be + * provided in your enviornment in order to use dwc_os.h with the debug and + * tracing message functionality. + * + * @subsection thread Threading + * + * WUDEV Core must be run on an operating system that provides for multiple + * threads/processes. Threading can be implemented in many ways, even in + * embedded systems without an operating system. At the bare minimum, the + * system should be able to start any number of processes at any time to handle + * special work. It need not be a pre-emptive system. Process context can + * change upon a call to a blocking function. The hardware interrupt context + * that calls the module's ISR() function must be differentiable from process + * context, even if your processes are impemented via a hardware interrupt. + * Further locking mechanism between process must exist (or be implemented), and + * process context must have a way to disable interrupts for a period of time to + * lock them out. If all of this exists, the functions in dwc_os.h related to + * threading should be able to be implemented with the defined behavior. + * + */ diff --git a/drivers/usb/host/dwc_common_port/usb.h b/drivers/usb/host/dwc_common_port/usb.h new file mode 100644 index 000000000000..2ee425239247 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/usb.h @@ -0,0 +1,850 @@ +/* + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Lennart Augustsson (lennart@augustsson.net) at + * Carlstedt Research & Technology. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* Modified by Synopsys, Inc, 12/12/2007 */ + + +#ifndef _USB_H_ +#define _USB_H_ + +#include "dwc_os.h" + +/* + * The USB records contain some unaligned little-endian word + * components. The U[SG]ETW macros take care of both the alignment + * and endian problem and should always be used to access non-byte + * values. + */ +typedef u_int8_t uByte; +typedef u_int8_t uWord[2]; +typedef u_int8_t uDWord[4]; + +#define USETW2(w,h,l) ((w)[0] = (u_int8_t)(l), (w)[1] = (u_int8_t)(h)) + +#if 1 +#define UGETW(w) ((w)[0] | ((w)[1] << 8)) +#define USETW(w,v) ((w)[0] = (u_int8_t)(v), (w)[1] = (u_int8_t)((v) >> 8)) +#define UGETDW(w) ((w)[0] | ((w)[1] << 8) | ((w)[2] << 16) | ((w)[3] << 24)) +#define USETDW(w,v) ((w)[0] = (u_int8_t)(v), \ + (w)[1] = (u_int8_t)((v) >> 8), \ + (w)[2] = (u_int8_t)((v) >> 16), \ + (w)[3] = (u_int8_t)((v) >> 24)) +#else +/* + * On little-endian machines that can handle unanliged accesses + * (e.g. i386) these macros can be replaced by the following. + */ +#define UGETW(w) (*(u_int16_t *)(w)) +#define USETW(w,v) (*(u_int16_t *)(w) = (v)) +#define UGETDW(w) (*(u_int32_t *)(w)) +#define USETDW(w,v) (*(u_int32_t *)(w) = (v)) +#endif + +#define UPACKED __attribute__((__packed__)) + +typedef struct { + uByte bmRequestType; + uByte bRequest; + uWord wValue; + uWord wIndex; + uWord wLength; +} UPACKED usb_device_request_t; + +#define UT_GET_DIR(a) ((a) & 0x80) +#define UT_WRITE 0x00 +#define UT_READ 0x80 + +#define UT_GET_TYPE(a) ((a) & 0x60) +#define UT_STANDARD 0x00 +#define UT_CLASS 0x20 +#define UT_VENDOR 0x40 + +#define UT_GET_RECIPIENT(a) ((a) & 0x1f) +#define UT_DEVICE 0x00 +#define UT_INTERFACE 0x01 +#define UT_ENDPOINT 0x02 +#define UT_OTHER 0x03 + +#define UT_READ_DEVICE (UT_READ | UT_STANDARD | UT_DEVICE) +#define UT_READ_INTERFACE (UT_READ | UT_STANDARD | UT_INTERFACE) +#define UT_READ_ENDPOINT (UT_READ | UT_STANDARD | UT_ENDPOINT) +#define UT_WRITE_DEVICE (UT_WRITE | UT_STANDARD | UT_DEVICE) +#define UT_WRITE_INTERFACE (UT_WRITE | UT_STANDARD | UT_INTERFACE) +#define UT_WRITE_ENDPOINT (UT_WRITE | UT_STANDARD | UT_ENDPOINT) +#define UT_READ_CLASS_DEVICE (UT_READ | UT_CLASS | UT_DEVICE) +#define UT_READ_CLASS_INTERFACE (UT_READ | UT_CLASS | UT_INTERFACE) +#define UT_READ_CLASS_OTHER (UT_READ | UT_CLASS | UT_OTHER) +#define UT_READ_CLASS_ENDPOINT (UT_READ | UT_CLASS | UT_ENDPOINT) +#define UT_WRITE_CLASS_DEVICE (UT_WRITE | UT_CLASS | UT_DEVICE) +#define UT_WRITE_CLASS_INTERFACE (UT_WRITE | UT_CLASS | UT_INTERFACE) +#define UT_WRITE_CLASS_OTHER (UT_WRITE | UT_CLASS | UT_OTHER) +#define UT_WRITE_CLASS_ENDPOINT (UT_WRITE | UT_CLASS | UT_ENDPOINT) +#define UT_READ_VENDOR_DEVICE (UT_READ | UT_VENDOR | UT_DEVICE) +#define UT_READ_VENDOR_INTERFACE (UT_READ | UT_VENDOR | UT_INTERFACE) +#define UT_READ_VENDOR_OTHER (UT_READ | UT_VENDOR | UT_OTHER) +#define UT_READ_VENDOR_ENDPOINT (UT_READ | UT_VENDOR | UT_ENDPOINT) +#define UT_WRITE_VENDOR_DEVICE (UT_WRITE | UT_VENDOR | UT_DEVICE) +#define UT_WRITE_VENDOR_INTERFACE (UT_WRITE | UT_VENDOR | UT_INTERFACE) +#define UT_WRITE_VENDOR_OTHER (UT_WRITE | UT_VENDOR | UT_OTHER) +#define UT_WRITE_VENDOR_ENDPOINT (UT_WRITE | UT_VENDOR | UT_ENDPOINT) + +/* Requests */ +#define UR_GET_STATUS 0x00 +#define USTAT_STANDARD_STATUS 0x00 +#define WUSTAT_WUSB_FEATURE 0x01 +#define WUSTAT_CHANNEL_INFO 0x02 +#define WUSTAT_RECEIVED_DATA 0x03 +#define WUSTAT_MAS_AVAILABILITY 0x04 +#define WUSTAT_CURRENT_TRANSMIT_POWER 0x05 +#define UR_CLEAR_FEATURE 0x01 +#define UR_SET_FEATURE 0x03 +#define UR_SET_AND_TEST_FEATURE 0x0c +#define UR_SET_ADDRESS 0x05 +#define UR_GET_DESCRIPTOR 0x06 +#define UDESC_DEVICE 0x01 +#define UDESC_CONFIG 0x02 +#define UDESC_STRING 0x03 +#define UDESC_INTERFACE 0x04 +#define UDESC_ENDPOINT 0x05 +#define UDESC_DEVICE_QUALIFIER 0x06 +#define UDESC_OTHER_SPEED_CONFIGURATION 0x07 +#define UDESC_INTERFACE_POWER 0x08 +#define UDESC_OTG 0x09 +#define WUDESC_SECURITY 0x0c +#define WUDESC_KEY 0x0d +#define WUD_GET_KEY_INDEX(_wValue_) ((_wValue_) & 0xf) +#define WUD_GET_KEY_TYPE(_wValue_) (((_wValue_) & 0x30) >> 4) +#define WUD_KEY_TYPE_ASSOC 0x01 +#define WUD_KEY_TYPE_GTK 0x02 +#define WUD_GET_KEY_ORIGIN(_wValue_) (((_wValue_) & 0x40) >> 6) +#define WUD_KEY_ORIGIN_HOST 0x00 +#define WUD_KEY_ORIGIN_DEVICE 0x01 +#define WUDESC_ENCRYPTION_TYPE 0x0e +#define WUDESC_BOS 0x0f +#define WUDESC_DEVICE_CAPABILITY 0x10 +#define WUDESC_WIRELESS_ENDPOINT_COMPANION 0x11 +#define UDESC_CS_DEVICE 0x21 /* class specific */ +#define UDESC_CS_CONFIG 0x22 +#define UDESC_CS_STRING 0x23 +#define UDESC_CS_INTERFACE 0x24 +#define UDESC_CS_ENDPOINT 0x25 +#define UDESC_HUB 0x29 +#define UR_SET_DESCRIPTOR 0x07 +#define UR_GET_CONFIG 0x08 +#define UR_SET_CONFIG 0x09 +#define UR_GET_INTERFACE 0x0a +#define UR_SET_INTERFACE 0x0b +#define UR_SYNCH_FRAME 0x0c +#define WUR_SET_ENCRYPTION 0x0d +#define WUR_GET_ENCRYPTION 0x0e +#define WUR_SET_HANDSHAKE 0x0f +#define WUR_GET_HANDSHAKE 0x10 +#define WUR_SET_CONNECTION 0x11 +#define WUR_SET_SECURITY_DATA 0x12 +#define WUR_GET_SECURITY_DATA 0x13 +#define WUR_SET_WUSB_DATA 0x14 +#define WUDATA_DRPIE_INFO 0x01 +#define WUDATA_TRANSMIT_DATA 0x02 +#define WUDATA_TRANSMIT_PARAMS 0x03 +#define WUDATA_RECEIVE_PARAMS 0x04 +#define WUDATA_TRANSMIT_POWER 0x05 +#define WUR_LOOPBACK_DATA_WRITE 0x15 +#define WUR_LOOPBACK_DATA_READ 0x16 +#define WUR_SET_INTERFACE_DS 0x17 + +/* Feature numbers */ +#define UF_ENDPOINT_HALT 0 +#define UF_DEVICE_REMOTE_WAKEUP 1 +#define UF_TEST_MODE 2 +#define UF_DEVICE_B_HNP_ENABLE 3 +#define UF_DEVICE_A_HNP_SUPPORT 4 +#define UF_DEVICE_A_ALT_HNP_SUPPORT 5 +#define WUF_WUSB 3 +#define WUF_TX_DRPIE 0x0 +#define WUF_DEV_XMIT_PACKET 0x1 +#define WUF_COUNT_PACKETS 0x2 +#define WUF_CAPTURE_PACKETS 0x3 + +/* Class requests from the USB 2.0 hub spec, table 11-15 */ +#define UCR_CLEAR_HUB_FEATURE (0x2000 | UR_CLEAR_FEATURE) +#define UCR_CLEAR_PORT_FEATURE (0x2300 | UR_CLEAR_FEATURE) +#define UCR_GET_HUB_DESCRIPTOR (0xa000 | UR_GET_DESCRIPTOR) +#define UCR_GET_HUB_STATUS (0xa000 | UR_GET_STATUS) +#define UCR_GET_PORT_STATUS (0xa300 | UR_GET_STATUS) +#define UCR_SET_HUB_FEATURE (0x2000 | UR_SET_FEATURE) +#define UCR_SET_PORT_FEATURE (0x2300 | UR_SET_FEATURE) +#define UCR_SET_AND_TEST_PORT_FEATURE (0xa300 | UR_SET_AND_TEST_FEATURE) + +typedef struct { + uByte bLength; + uByte bDescriptorType; + uByte bDescriptorSubtype; +} UPACKED usb_descriptor_t; + +typedef struct { + uByte bLength; + uByte bDescriptorType; + uWord bcdUSB; +#define UD_USB_2_0 0x0200 +#define UD_IS_USB2(d) (UGETW((d)->bcdUSB) >= UD_USB_2_0) + uByte bDeviceClass; + uByte bDeviceSubClass; + uByte bDeviceProtocol; + uByte bMaxPacketSize; + /* The fields below are not part of the initial descriptor. */ + uWord idVendor; + uWord idProduct; + uWord bcdDevice; + uByte iManufacturer; + uByte iProduct; + uByte iSerialNumber; + uByte bNumConfigurations; +} UPACKED usb_device_descriptor_t; +#define USB_DEVICE_DESCRIPTOR_SIZE 18 + +typedef struct { + uByte bLength; + uByte bDescriptorType; + uWord wTotalLength; + uByte bNumInterface; + uByte bConfigurationValue; + uByte iConfiguration; + uByte bmAttributes; +#define UC_BUS_POWERED 0x80 +#define UC_SELF_POWERED 0x40 +#define UC_REMOTE_WAKEUP 0x20 + uByte bMaxPower; /* max current in 2 mA units */ +#define UC_POWER_FACTOR 2 +} UPACKED usb_config_descriptor_t; +#define USB_CONFIG_DESCRIPTOR_SIZE 9 + +typedef struct { + uByte bLength; + uByte bDescriptorType; + uByte bInterfaceNumber; + uByte bAlternateSetting; + uByte bNumEndpoints; + uByte bInterfaceClass; + uByte bInterfaceSubClass; + uByte bInterfaceProtocol; + uByte iInterface; +} UPACKED usb_interface_descriptor_t; +#define USB_INTERFACE_DESCRIPTOR_SIZE 9 + +typedef struct { + uByte bLength; + uByte bDescriptorType; + uByte bEndpointAddress; +#define UE_GET_DIR(a) ((a) & 0x80) +#define UE_SET_DIR(a,d) ((a) | (((d)&1) << 7)) +#define UE_DIR_IN 0x80 +#define UE_DIR_OUT 0x00 +#define UE_ADDR 0x0f +#define UE_GET_ADDR(a) ((a) & UE_ADDR) + uByte bmAttributes; +#define UE_XFERTYPE 0x03 +#define UE_CONTROL 0x00 +#define UE_ISOCHRONOUS 0x01 +#define UE_BULK 0x02 +#define UE_INTERRUPT 0x03 +#define UE_GET_XFERTYPE(a) ((a) & UE_XFERTYPE) +#define UE_ISO_TYPE 0x0c +#define UE_ISO_ASYNC 0x04 +#define UE_ISO_ADAPT 0x08 +#define UE_ISO_SYNC 0x0c +#define UE_GET_ISO_TYPE(a) ((a) & UE_ISO_TYPE) + uWord wMaxPacketSize; + uByte bInterval; +} UPACKED usb_endpoint_descriptor_t; +#define USB_ENDPOINT_DESCRIPTOR_SIZE 7 + +typedef struct { + uByte bLength; + uByte bDescriptorType; + uWord bString[127]; +} UPACKED usb_string_descriptor_t; +#define USB_MAX_STRING_LEN 128 +#define USB_LANGUAGE_TABLE 0 /* # of the string language id table */ + +/* Hub specific request */ +#define UR_GET_BUS_STATE 0x02 +#define UR_CLEAR_TT_BUFFER 0x08 +#define UR_RESET_TT 0x09 +#define UR_GET_TT_STATE 0x0a +#define UR_STOP_TT 0x0b + +/* Hub features */ +#define UHF_C_HUB_LOCAL_POWER 0 +#define UHF_C_HUB_OVER_CURRENT 1 +#define UHF_PORT_CONNECTION 0 +#define UHF_PORT_ENABLE 1 +#define UHF_PORT_SUSPEND 2 +#define UHF_PORT_OVER_CURRENT 3 +#define UHF_PORT_RESET 4 +#define UHF_PORT_L1 5 +#define UHF_PORT_POWER 8 +#define UHF_PORT_LOW_SPEED 9 +#define UHF_PORT_HIGH_SPEED 10 +#define UHF_C_PORT_CONNECTION 16 +#define UHF_C_PORT_ENABLE 17 +#define UHF_C_PORT_SUSPEND 18 +#define UHF_C_PORT_OVER_CURRENT 19 +#define UHF_C_PORT_RESET 20 +#define UHF_C_PORT_L1 23 +#define UHF_PORT_TEST 21 +#define UHF_PORT_INDICATOR 22 + +typedef struct { + uByte bDescLength; + uByte bDescriptorType; + uByte bNbrPorts; + uWord wHubCharacteristics; +#define UHD_PWR 0x0003 +#define UHD_PWR_GANGED 0x0000 +#define UHD_PWR_INDIVIDUAL 0x0001 +#define UHD_PWR_NO_SWITCH 0x0002 +#define UHD_COMPOUND 0x0004 +#define UHD_OC 0x0018 +#define UHD_OC_GLOBAL 0x0000 +#define UHD_OC_INDIVIDUAL 0x0008 +#define UHD_OC_NONE 0x0010 +#define UHD_TT_THINK 0x0060 +#define UHD_TT_THINK_8 0x0000 +#define UHD_TT_THINK_16 0x0020 +#define UHD_TT_THINK_24 0x0040 +#define UHD_TT_THINK_32 0x0060 +#define UHD_PORT_IND 0x0080 + uByte bPwrOn2PwrGood; /* delay in 2 ms units */ +#define UHD_PWRON_FACTOR 2 + uByte bHubContrCurrent; + uByte DeviceRemovable[32]; /* max 255 ports */ +#define UHD_NOT_REMOV(desc, i) \ + (((desc)->DeviceRemovable[(i)/8] >> ((i) % 8)) & 1) + /* deprecated */ uByte PortPowerCtrlMask[1]; +} UPACKED usb_hub_descriptor_t; +#define USB_HUB_DESCRIPTOR_SIZE 9 /* includes deprecated PortPowerCtrlMask */ + +typedef struct { + uByte bLength; + uByte bDescriptorType; + uWord bcdUSB; + uByte bDeviceClass; + uByte bDeviceSubClass; + uByte bDeviceProtocol; + uByte bMaxPacketSize0; + uByte bNumConfigurations; + uByte bReserved; +} UPACKED usb_device_qualifier_t; +#define USB_DEVICE_QUALIFIER_SIZE 10 + +typedef struct { + uByte bLength; + uByte bDescriptorType; + uByte bmAttributes; +#define UOTG_SRP 0x01 +#define UOTG_HNP 0x02 +} UPACKED usb_otg_descriptor_t; + +/* OTG feature selectors */ +#define UOTG_B_HNP_ENABLE 3 +#define UOTG_A_HNP_SUPPORT 4 +#define UOTG_A_ALT_HNP_SUPPORT 5 + +typedef struct { + uWord wStatus; +/* Device status flags */ +#define UDS_SELF_POWERED 0x0001 +#define UDS_REMOTE_WAKEUP 0x0002 +/* Endpoint status flags */ +#define UES_HALT 0x0001 +} UPACKED usb_status_t; + +typedef struct { + uWord wHubStatus; +#define UHS_LOCAL_POWER 0x0001 +#define UHS_OVER_CURRENT 0x0002 + uWord wHubChange; +} UPACKED usb_hub_status_t; + +typedef struct { + uWord wPortStatus; +#define UPS_CURRENT_CONNECT_STATUS 0x0001 +#define UPS_PORT_ENABLED 0x0002 +#define UPS_SUSPEND 0x0004 +#define UPS_OVERCURRENT_INDICATOR 0x0008 +#define UPS_RESET 0x0010 +#define UPS_PORT_POWER 0x0100 +#define UPS_LOW_SPEED 0x0200 +#define UPS_HIGH_SPEED 0x0400 +#define UPS_PORT_TEST 0x0800 +#define UPS_PORT_INDICATOR 0x1000 + uWord wPortChange; +#define UPS_C_CONNECT_STATUS 0x0001 +#define UPS_C_PORT_ENABLED 0x0002 +#define UPS_C_SUSPEND 0x0004 +#define UPS_C_OVERCURRENT_INDICATOR 0x0008 +#define UPS_C_PORT_RESET 0x0010 +} UPACKED usb_port_status_t; + +/* Device class codes */ +#define UDCLASS_IN_INTERFACE 0x00 +#define UDCLASS_COMM 0x02 +#define UDCLASS_HUB 0x09 +#define UDSUBCLASS_HUB 0x00 +#define UDPROTO_FSHUB 0x00 +#define UDPROTO_HSHUBSTT 0x01 +#define UDPROTO_HSHUBMTT 0x02 +#define UDCLASS_DIAGNOSTIC 0xdc +#define UDCLASS_WIRELESS 0xe0 +#define UDSUBCLASS_RF 0x01 +#define UDPROTO_BLUETOOTH 0x01 +#define UDCLASS_VENDOR 0xff + +/* Interface class codes */ +#define UICLASS_UNSPEC 0x00 + +#define UICLASS_AUDIO 0x01 +#define UISUBCLASS_AUDIOCONTROL 1 +#define UISUBCLASS_AUDIOSTREAM 2 +#define UISUBCLASS_MIDISTREAM 3 + +#define UICLASS_CDC 0x02 /* communication */ +#define UISUBCLASS_DIRECT_LINE_CONTROL_MODEL 1 +#define UISUBCLASS_ABSTRACT_CONTROL_MODEL 2 +#define UISUBCLASS_TELEPHONE_CONTROL_MODEL 3 +#define UISUBCLASS_MULTICHANNEL_CONTROL_MODEL 4 +#define UISUBCLASS_CAPI_CONTROLMODEL 5 +#define UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL 6 +#define UISUBCLASS_ATM_NETWORKING_CONTROL_MODEL 7 +#define UIPROTO_CDC_AT 1 + +#define UICLASS_HID 0x03 +#define UISUBCLASS_BOOT 1 +#define UIPROTO_BOOT_KEYBOARD 1 + +#define UICLASS_PHYSICAL 0x05 + +#define UICLASS_IMAGE 0x06 + +#define UICLASS_PRINTER 0x07 +#define UISUBCLASS_PRINTER 1 +#define UIPROTO_PRINTER_UNI 1 +#define UIPROTO_PRINTER_BI 2 +#define UIPROTO_PRINTER_1284 3 + +#define UICLASS_MASS 0x08 +#define UISUBCLASS_RBC 1 +#define UISUBCLASS_SFF8020I 2 +#define UISUBCLASS_QIC157 3 +#define UISUBCLASS_UFI 4 +#define UISUBCLASS_SFF8070I 5 +#define UISUBCLASS_SCSI 6 +#define UIPROTO_MASS_CBI_I 0 +#define UIPROTO_MASS_CBI 1 +#define UIPROTO_MASS_BBB_OLD 2 /* Not in the spec anymore */ +#define UIPROTO_MASS_BBB 80 /* 'P' for the Iomega Zip drive */ + +#define UICLASS_HUB 0x09 +#define UISUBCLASS_HUB 0 +#define UIPROTO_FSHUB 0 +#define UIPROTO_HSHUBSTT 0 /* Yes, same as previous */ +#define UIPROTO_HSHUBMTT 1 + +#define UICLASS_CDC_DATA 0x0a +#define UISUBCLASS_DATA 0 +#define UIPROTO_DATA_ISDNBRI 0x30 /* Physical iface */ +#define UIPROTO_DATA_HDLC 0x31 /* HDLC */ +#define UIPROTO_DATA_TRANSPARENT 0x32 /* Transparent */ +#define UIPROTO_DATA_Q921M 0x50 /* Management for Q921 */ +#define UIPROTO_DATA_Q921 0x51 /* Data for Q921 */ +#define UIPROTO_DATA_Q921TM 0x52 /* TEI multiplexer for Q921 */ +#define UIPROTO_DATA_V42BIS 0x90 /* Data compression */ +#define UIPROTO_DATA_Q931 0x91 /* Euro-ISDN */ +#define UIPROTO_DATA_V120 0x92 /* V.24 rate adaption */ +#define UIPROTO_DATA_CAPI 0x93 /* CAPI 2.0 commands */ +#define UIPROTO_DATA_HOST_BASED 0xfd /* Host based driver */ +#define UIPROTO_DATA_PUF 0xfe /* see Prot. Unit Func. Desc.*/ +#define UIPROTO_DATA_VENDOR 0xff /* Vendor specific */ + +#define UICLASS_SMARTCARD 0x0b + +/*#define UICLASS_FIRM_UPD 0x0c*/ + +#define UICLASS_SECURITY 0x0d + +#define UICLASS_DIAGNOSTIC 0xdc + +#define UICLASS_WIRELESS 0xe0 +#define UISUBCLASS_RF 0x01 +#define UIPROTO_BLUETOOTH 0x01 + +#define UICLASS_APPL_SPEC 0xfe +#define UISUBCLASS_FIRMWARE_DOWNLOAD 1 +#define UISUBCLASS_IRDA 2 +#define UIPROTO_IRDA 0 + +#define UICLASS_VENDOR 0xff + + +#define USB_HUB_MAX_DEPTH 5 + +/* + * Minimum time a device needs to be powered down to go through + * a power cycle. XXX Are these time in the spec? + */ +#define USB_POWER_DOWN_TIME 200 /* ms */ +#define USB_PORT_POWER_DOWN_TIME 100 /* ms */ + +#if 0 +/* These are the values from the spec. */ +#define USB_PORT_RESET_DELAY 10 /* ms */ +#define USB_PORT_ROOT_RESET_DELAY 50 /* ms */ +#define USB_PORT_RESET_RECOVERY 10 /* ms */ +#define USB_PORT_POWERUP_DELAY 100 /* ms */ +#define USB_SET_ADDRESS_SETTLE 2 /* ms */ +#define USB_RESUME_DELAY (20*5) /* ms */ +#define USB_RESUME_WAIT 10 /* ms */ +#define USB_RESUME_RECOVERY 10 /* ms */ +#define USB_EXTRA_POWER_UP_TIME 0 /* ms */ +#else +/* Allow for marginal (i.e. non-conforming) devices. */ +#define USB_PORT_RESET_DELAY 50 /* ms */ +#define USB_PORT_ROOT_RESET_DELAY 250 /* ms */ +#define USB_PORT_RESET_RECOVERY 250 /* ms */ +#define USB_PORT_POWERUP_DELAY 300 /* ms */ +#define USB_SET_ADDRESS_SETTLE 10 /* ms */ +#define USB_RESUME_DELAY (50*5) /* ms */ +#define USB_RESUME_WAIT 50 /* ms */ +#define USB_RESUME_RECOVERY 50 /* ms */ +#define USB_EXTRA_POWER_UP_TIME 20 /* ms */ +#endif + +#define USB_MIN_POWER 100 /* mA */ +#define USB_MAX_POWER 500 /* mA */ + +#define USB_BUS_RESET_DELAY 100 /* ms XXX?*/ + + +#define USB_UNCONFIG_NO 0 +#define USB_UNCONFIG_INDEX (-1) + +/*** ioctl() related stuff ***/ + +struct usb_ctl_request { + int ucr_addr; + usb_device_request_t ucr_request; + void *ucr_data; + int ucr_flags; +#define USBD_SHORT_XFER_OK 0x04 /* allow short reads */ + int ucr_actlen; /* actual length transferred */ +}; + +struct usb_alt_interface { + int uai_config_index; + int uai_interface_index; + int uai_alt_no; +}; + +#define USB_CURRENT_CONFIG_INDEX (-1) +#define USB_CURRENT_ALT_INDEX (-1) + +struct usb_config_desc { + int ucd_config_index; + usb_config_descriptor_t ucd_desc; +}; + +struct usb_interface_desc { + int uid_config_index; + int uid_interface_index; + int uid_alt_index; + usb_interface_descriptor_t uid_desc; +}; + +struct usb_endpoint_desc { + int ued_config_index; + int ued_interface_index; + int ued_alt_index; + int ued_endpoint_index; + usb_endpoint_descriptor_t ued_desc; +}; + +struct usb_full_desc { + int ufd_config_index; + u_int ufd_size; + u_char *ufd_data; +}; + +struct usb_string_desc { + int usd_string_index; + int usd_language_id; + usb_string_descriptor_t usd_desc; +}; + +struct usb_ctl_report_desc { + int ucrd_size; + u_char ucrd_data[1024]; /* filled data size will vary */ +}; + +typedef struct { u_int32_t cookie; } usb_event_cookie_t; + +#define USB_MAX_DEVNAMES 4 +#define USB_MAX_DEVNAMELEN 16 +struct usb_device_info { + u_int8_t udi_bus; + u_int8_t udi_addr; /* device address */ + usb_event_cookie_t udi_cookie; + char udi_product[USB_MAX_STRING_LEN]; + char udi_vendor[USB_MAX_STRING_LEN]; + char udi_release[8]; + u_int16_t udi_productNo; + u_int16_t udi_vendorNo; + u_int16_t udi_releaseNo; + u_int8_t udi_class; + u_int8_t udi_subclass; + u_int8_t udi_protocol; + u_int8_t udi_config; + u_int8_t udi_speed; +#define USB_SPEED_LOW 1 +#define USB_SPEED_FULL 2 +#define USB_SPEED_HIGH 3 + int udi_power; /* power consumption in mA, 0 if selfpowered */ + int udi_nports; + char udi_devnames[USB_MAX_DEVNAMES][USB_MAX_DEVNAMELEN]; + u_int8_t udi_ports[16];/* hub only: addresses of devices on ports */ +#define USB_PORT_ENABLED 0xff +#define USB_PORT_SUSPENDED 0xfe +#define USB_PORT_POWERED 0xfd +#define USB_PORT_DISABLED 0xfc +}; + +struct usb_ctl_report { + int ucr_report; + u_char ucr_data[1024]; /* filled data size will vary */ +}; + +struct usb_device_stats { + u_long uds_requests[4]; /* indexed by transfer type UE_* */ +}; + + + + +#define WUSB_MIN_IE 0x80 +#define WUSB_WCTA_IE 0x80 +#define WUSB_WCONNECTACK_IE 0x81 +#define WUSB_WHOSTINFO_IE 0x82 +#define WUHI_GET_CA(_bmAttributes_) ((_bmAttributes_) & 0x3) +#define WUHI_CA_RECONN 0x00 +#define WUHI_CA_LIMITED 0x01 +#define WUHI_CA_ALL 0x03 +#define WUHI_GET_MLSI(_bmAttributes_) (((_bmAttributes_) & 0x38) >> 3) +#define WUSB_WCHCHANGEANNOUNCE_IE 0x83 +#define WUSB_WDEV_DISCONNECT_IE 0x84 +#define WUSB_WHOST_DISCONNECT_IE 0x85 +#define WUSB_WRELEASE_CHANNEL_IE 0x86 +#define WUSB_WWORK_IE 0x87 +#define WUSB_WCHANNEL_STOP_IE 0x88 +#define WUSB_WDEV_KEEPALIVE_IE 0x89 +#define WUSB_WISOCH_DISCARD_IE 0x8A +#define WUSB_WRESETDEVICE_IE 0x8B +#define WUSB_WXMIT_PACKET_ADJUST_IE 0x8C +#define WUSB_MAX_IE 0x8C + +/* Device Notification Types */ + +#define WUSB_DN_MIN 0x01 +#define WUSB_DN_CONNECT 0x01 +# define WUSB_DA_OLDCONN 0x00 +# define WUSB_DA_NEWCONN 0x01 +# define WUSB_DA_SELF_BEACON 0x02 +# define WUSB_DA_DIR_BEACON 0x04 +# define WUSB_DA_NO_BEACON 0x06 +#define WUSB_DN_DISCONNECT 0x02 +#define WUSB_DN_EPRDY 0x03 +#define WUSB_DN_MASAVAILCHANGED 0x04 +#define WUSB_DN_REMOTEWAKEUP 0x05 +#define WUSB_DN_SLEEP 0x06 +#define WUSB_DN_ALIVE 0x07 +#define WUSB_DN_MAX 0x07 + + +/* WUSB Handshake Data. Used during the SET/GET HANDSHAKE requests */ +typedef struct wusb_hndshk_data { + uint8_t bMessageNumber; + uint8_t bStatus; + uint8_t tTKID[3]; + uint8_t bReserved; + uint8_t CDID[16]; + uint8_t Nonce[16]; + uint8_t MIC[8]; +} UPACKED wusb_hndshk_data_t; +#define WUSB_HANDSHAKE_LEN_FOR_MIC 38 + +/* WUSB Connection Context */ +typedef struct wusb_conn_context { + uint8_t CHID [16]; + uint8_t CDID [16]; + uint8_t CK [16]; +} UPACKED wusb_conn_context_t; + +/* WUSB Security Descriptor */ +typedef struct wusb_security_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumEncryptionTypes; +} UPACKED wusb_security_desc_t; + +/* WUSB Encryption Type Descriptor */ +typedef struct wusb_encrypt_type_desc { + uint8_t bLength; + uint8_t bDescriptorType; + + uint8_t bEncryptionType; +#define WUETD_UNSECURE 0 +#define WUETD_WIRED 1 +#define WUETD_CCM_1 2 +#define WUETD_RSA_1 3 + + uint8_t bEncryptionValue; + uint8_t bAuthKeyIndex; +} UPACKED wusb_encrypt_type_desc_t; + +/* WUSB Key Descriptor */ +typedef struct wusb_key_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t tTKID[3]; + uint8_t bReserved; + uint8_t KeyData[1]; /* variable length */ +} UPACKED wusb_key_desc_t; + +/* WUSB BOS Descriptor (Binary device Object Store) */ +typedef struct wusb_bos_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumDeviceCaps; +} UPACKED wusb_bos_desc_t; + + +/* Device Capability Type Codes */ +#define WUSB_DEVICE_CAPABILITY_WIRELESS_USB 0x01 + +/* Device Capability Descriptor */ +typedef struct wusb_dev_cap_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint8_t caps[1]; /* Variable length */ +} UPACKED wusb_dev_cap_desc_t; + +/* Device Capability Descriptor */ +typedef struct wusb_dev_cap_uwb_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint8_t bmAttributes; + uint16_t wPHYRates; /* Bitmap */ + uint8_t bmTFITXPowerInfo; + uint8_t bmFFITXPowerInfo; + uint16_t bmBandGroup; + uint8_t bReserved; +} UPACKED wusb_dev_cap_uwb_desc_t; + +/* Wireless USB Endpoint Companion Descriptor */ +typedef struct wusb_endpoint_companion_desc { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bMaxBurst; + uint8_t bMaxSequence; + uint16_t wMaxStreamDelay; + uint16_t wOverTheAirPacketSize; + uint8_t bOverTheAirInterval; + uint8_t bmCompAttributes; +} UPACKED wusb_endpoint_companion_desc_t; + + +/* Wireless USB Numeric Association M1 Data Structure */ +typedef struct wusb_m1_data { + uint8_t version; + uint16_t langId; + uint8_t deviceFriendlyNameLength; + uint8_t sha_256_m3[32]; + uint8_t deviceFriendlyName[256]; +} UPACKED wusb_m1_data_t; + +typedef struct wusb_m2_data { + uint8_t version; + uint16_t langId; + uint8_t hostFriendlyNameLength; + uint8_t pkh[384]; + uint8_t hostFriendlyName[256]; +} UPACKED wusb_m2_data_t; + +typedef struct wusb_m3_data { + uint8_t pkd[384]; + uint8_t nd; +} UPACKED wusb_m3_data_t; + +typedef struct wusb_m4_data { + uint32_t _attributeTypeIdAndLength_1; + uint16_t associationTypeId; + + uint32_t _attributeTypeIdAndLength_2; + uint16_t associationSubTypeId; + + uint32_t _attributeTypeIdAndLength_3; + uint32_t length; + + uint32_t _attributeTypeIdAndLength_4; + uint32_t associationStatus; + + uint32_t _attributeTypeIdAndLength_5; + uint8_t chid[16]; + + uint32_t _attributeTypeIdAndLength_6; + uint8_t cdid[16]; + + uint32_t _attributeTypeIdAndLength_7; + uint8_t bandGroups[2]; +} UPACKED wusb_m4_data_t; + + + + +#endif /* _USB_H_ */ diff --git a/drivers/usb/host/dwc_otg/Makefile b/drivers/usb/host/dwc_otg/Makefile new file mode 100644 index 000000000000..161fe371c8aa --- /dev/null +++ b/drivers/usb/host/dwc_otg/Makefile @@ -0,0 +1,78 @@ +# +# Makefile for DWC_otg Highspeed USB controller driver +# + +ifneq ($(KERNELRELEASE),) + +ifeq ($(BUS_INTERFACE),) + # BUS_INTERFACE = -DLM_INTERFACE + BUS_INTERFACE = -DPLATFORM_INTERFACE=1 +endif + +CPPFLAGS += -DDEBUG + +# Use one of the following flags to compile the software in host-only or +# device-only mode. +#CPPFLAGS += -DDWC_HOST_ONLY +#CPPFLAGS += -DDWC_DEVICE_ONLY + +CPPFLAGS += -Dlinux -DDWC_HS_ELECT_TST +#CGG: CPPFLAGS += -DDWC_EN_ISOC +CPPFLAGS += -I$(obj)/../dwc_common_port +#CPPFLAGS += -I$(PORTLIB) +CPPFLAGS += -DDWC_LINUX +CPPFLAGS += $(CFI) +CPPFLAGS += $(BUS_INTERFACE) + +obj-$(CONFIG_USB_DWCOTG) += dwc_otg.o + +dwc_otg-objs := dwc_otg_driver.o dwc_otg_attr.o +dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o +dwc_otg-objs += dwc_otg_pcd_linux.o dwc_otg_pcd.o dwc_otg_pcd_intr.o +dwc_otg-objs += dwc_otg_hcd.o dwc_otg_hcd_linux.o dwc_otg_hcd_intr.o dwc_otg_hcd_queue.o dwc_otg_hcd_ddma.o +ifneq ($(CFI),) +dwc_otg-objs += dwc_otg_cfi.o +endif + +kernrelwd := $(subst ., ,$(KERNELRELEASE)) +kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd)) + +ifneq ($(kernrel3),2.6.20) +EXTRA_CFLAGS += $(CPPFLAGS) +endif + +else + +PWD := $(shell pwd) +PORTLIB := $(PWD)/../dwc_common_port + +# Command paths +CTAGS := $(CTAGS) +DOXYGEN := $(DOXYGEN) + +default: portlib + $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules + +install: default +ifneq ($(INSTALL_MOD_PATH),) + $(MAKE) -C$(KDIR) M=$(PORTLIB) modules_install + $(MAKE) -C$(KDIR) M=$(PWD) modules_install +else + @echo "No install path defined" +endif + +portlib: + $(MAKE) -C$(KDIR) M=$(PORTLIB) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules + cp $(PORTLIB)/Module.symvers $(PWD)/ + +docs: $(wildcard *.[hc]) doc/doxygen.cfg + $(DOXYGEN) doc/doxygen.cfg + +tags: $(wildcard *.[hc]) + $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h) + + +clean: + rm -rf *.o *.ko .*cmd *.mod.c .tmp_versions + +endif diff --git a/drivers/usb/host/dwc_otg/doc/doxygen.cfg b/drivers/usb/host/dwc_otg/doc/doxygen.cfg new file mode 100644 index 000000000000..ddd0a1013a4b --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/doxygen.cfg @@ -0,0 +1,224 @@ +# Doxyfile 1.3.9.1 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = "DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver" +PROJECT_NUMBER = v2.90a +OUTPUT_DIRECTORY = ./doc/ +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = NO +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = NO +WARN_IF_DOC_ERROR = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = . +FILE_PATTERNS = *.c \ + *.h \ + ./linux/*.c \ + ./linux/*.h +RECURSIVE = NO +EXCLUDE = ./test/ \ + ./dwc_otg/.AppleDouble/ +EXCLUDE_SYMLINKS = YES +EXCLUDE_PATTERNS = *.mod.* +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +VERBATIM_HEADERS = NO +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = YES +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = DEVICE_ATTR DWC_EN_ISOC +EXPAND_AS_DEFINED = DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW DWC_OTG_DEVICE_ATTR_BITFIELD_STORE DWC_OTG_DEVICE_ATTR_BITFIELD_RW DWC_OTG_DEVICE_ATTR_BITFIELD_RO DWC_OTG_DEVICE_ATTR_REG_SHOW DWC_OTG_DEVICE_ATTR_REG_STORE DWC_OTG_DEVICE_ATTR_REG32_RW DWC_OTG_DEVICE_ATTR_REG32_RO DWC_EN_ISOC +SKIP_FUNCTION_MACROS = NO +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_DEPTH = 1000 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/drivers/usb/host/dwc_otg/doc/html/annotated.html b/drivers/usb/host/dwc_otg/doc/html/annotated.html new file mode 100644 index 000000000000..1ef51acd4ad7 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/annotated.html @@ -0,0 +1,120 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Structures + + + + + + +

DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver Data Structures

Here are the data structures with brief descriptions: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
_ddma_align_buffer_setupDescriptor DMA Alignment Buffer setup structure
_ddma_concat_buffer_setupDescriptor DMA Concatenation Buffer setup structure
_ddma_concat_buffer_setup_hdrDescriptor DMA Concatenation Buffer setup structure
_ddma_sg_buffer_setupDescriptor DMA SG Buffer setup structure (SG buffer)
_rx_fifo_size_setupTransmit FIFO Size setup structure
_tx_fifo_size_setupTransmit FIFO Size setup structure
cfi_all_features_headerThis structure is the header of the Core Features dataset returned to the Host
cfi_dma_buff
cfi_epThe CFI wrapper of the enabled and activated dwc_otg_pcd_ep structures
cfi_feature_desc_headerThis structure is a header of the Core Feature descriptor dataset returned to the Host after the VEN_CORE_GET_FEATURES request
cfi_opsThis is the interface for the CFI operations
cfi_stringThis structure describes a NULL terminated string referenced by its id field
cfi_usb_ctrlrequestStruct cfi_usb_ctrlrequest - the CFI implementation of the struct usb_ctrlrequest This structure encapsulates the standard usb_ctrlrequest and adds a pointer to the data returned in the data stage of a 3-stage Control Write requests
cfiobject
daint_dataThis union represents the bit fields in the Device All EP Interrupt and Mask Registers
dcfg_dataThis union represents the bit fields in the Device Configuration Register
dctl_dataThis union represents the bit fields in the Device Control Register
depctl_dataThis union represents the bit fields in the Device EP Control Register
deptsiz0_dataThis union represents the bit fields in the Device EP 0 Transfer Size Register
deptsiz_dataThis union represents the bit fields in the Device EP Transfer Size Register
dev_dma_desc_stsThis union represents the bit fields in the DMA Descriptor status quadlet
device_grxsts_dataThis union represents the bit fields in the Device Receive Status Read and Pop Registers (GRXSTSR, GRXSTSP) Read the register into the d32 element then read out the bits using the bit elements
diepint_dataThis union represents the bit fields in the Device IN EP Interrupt Register and the Device IN EP Common Mask Register
doepint_dataThis union represents the bit fields in the Device OUT EP Interrupt Registerand Device OUT EP Common Interrupt Mask Register
dsts_dataThis union represents the bit fields in the Device Status Register
dthrctl_dataThis union represents Threshold control Register
    +
  • Read and write the register into the d32 member
+
dtknq1_dataThis union represents the bit fields in the Device IN Token Queue Read Registers
dtxfsts_dataThis union represents the bit fields in the Transmit FIFO Status Register (DTXFSTS)
dwc_epThe dwc_ep structure represents the state of a single endpoint when acting in device mode
dwc_hcHost channel descriptor
dwc_otg_cil_callbacksDWC_otg CIL callback structure
dwc_otg_core_global_regsDWC_otg Core registers
dwc_otg_core_ifThe dwc_otg_core_if structure contains information needed to manage the DWC_otg controller acting in either host or device mode
dwc_otg_core_paramsThe following parameters may be specified when starting the module
dwc_otg_dev_dma_descDMA Descriptor structure
dwc_otg_dev_global_regsDevice Global Registers
dwc_otg_dev_ifThe dwc_otg_dev_if structure contains information needed to manage the DWC_otg controller acting in device mode
dwc_otg_dev_in_ep_regsDevice Logical IN Endpoint-Specific Registers
dwc_otg_dev_out_ep_regsDevice Logical OUT Endpoint-Specific Registers
dwc_otg_deviceThis structure is a wrapper that encapsulates the driver components used to manage a single DWC_otg controller
dwc_otg_driver_module_params
dwc_otg_hc_regsHost Channel Specific Registers
dwc_otg_hcdThis structure holds the state of the HCD, including the non-periodic and periodic schedules
dwc_otg_hcd::dwc_otg_hcd_internal_flagsInternal DWC HCD Flags
dwc_otg_hcd_function_ops
dwc_otg_hcd_iso_packet_desc
dwc_otg_hcd_pipe_info
dwc_otg_hcd_urb
dwc_otg_host_dma_descHost-mode DMA Descriptor structure
dwc_otg_host_global_regsThe Host Global Registers structure defines the size and relative field offsets for the Host Mode Global Registers
dwc_otg_host_ifOTG Host Interface Structure
dwc_otg_pcdDWC_otg PCD Structure
dwc_otg_pcd_epPCD EP structure
dwc_otg_pcd_function_opsFunction Driver Ops Data Structure
dwc_otg_pcd_requestDWC_otg request structure
dwc_otg_qhA Queue Head (QH) holds the static characteristics of an endpoint and maintains a list of transfers (QTDs) for that endpoint
dwc_otg_qtdA Queue Transfer Descriptor (QTD) holds the state of a bulk, control, interrupt, or isochronous transfer
fifosize_dataThis union represents the bit fields in the FIFO Size Registers (HPTXFSIZ, GNPTXFSIZ, DPTXFSIZn, DIEPTXFn)
gadget_wrapper
gahbcfg_dataThis union represents the bit fields of the Core AHB Configuration Register (GAHBCFG)
gi2cctl_dataThis union represents the bit fields in the I2C Control Register (I2CCTL)
gintmsk_dataThis union represents the bit fields of the Core Interrupt Mask Register (GINTMSK)
gintsts_dataThis union represents the bit fields of the Core Interrupt Register (GINTSTS)
glpmctl_dataThis union represents the bit fields of the Core LPM Configuration Register (GLPMCFG)
gnptxsts_dataThis union represents the bit fields in the Non-Periodic Transmit FIFO/Queue Status Register (GNPTXSTS)
gotgctl_dataThis union represents the bit fields of the Core OTG Control and Status Register (GOTGCTL)
gotgint_dataThis union represents the bit fields of the Core OTG Interrupt Register (GOTGINT)
grstctl_dataThis union represents the bit fields of the Core Reset Register (GRSTCTL)
gusbcfg_dataThis union represents the bit fields of the Core USB Configuration Register (GUSBCFG)
haint_dataThis union represents the bit fields in the Host All Interrupt Register
haintmsk_dataThis union represents the bit fields in the Host All Interrupt Register
hcchar_dataThis union represents the bit fields in the Host Channel Characteristics Register
hcdma_dataThis union represents the bit fields in the Host DMA Address Register used in Descriptor DMA mode
hcfg_dataThis union represents the bit fields in the Host Configuration Register
hcint_dataThis union represents the bit fields in the Host All Interrupt Register
hcintmsk_dataThis union represents the bit fields in the Host Channel Interrupt Mask Register
hcsplt_data
hctsiz_dataThis union represents the bit fields in the Host Channel Transfer Size Register
hfir_dataThis union represents the bit fields in the Host Frame Remaing/Number Register
hfnum_dataThis union represents the bit fields in the Host Frame Remaing/Number Register
host_dma_desc_stsThis union represents the bit fields in the DMA Descriptor status quadlet for host mode
host_grxsts_dataThis union represents the bit fields in the Host Receive Status Read and Pop Registers (GRXSTSR, GRXSTSP) Read the register into the d32 element then read out the bits using the bit elements
hprt0_dataThis union represents the bit fields in the Host Port Control and Status Register
hptxsts_data
hwcfg1_dataThis union represents the bit fields in the User HW Config1 Register
hwcfg2_dataThis union represents the bit fields in the User HW Config2 Register
hwcfg3_dataThis union represents the bit fields in the User HW Config3 Register
hwcfg4_dataThis union represents the bit fields in the User HW Config4 Register
iso_pkt_infoInformation for each ISOC packet
pcgcctl_dataThis union represents the bit fields in the Power and Clock Gating Control Register
wrapper_priv_data
zero_dev
+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/doxygen.css b/drivers/usb/host/dwc_otg/doc/html/doxygen.css new file mode 100644 index 000000000000..5d583694ed46 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/doxygen.css @@ -0,0 +1,358 @@ +BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { + font-family: Geneva, Arial, Helvetica, sans-serif; +} +BODY,TD { + font-size: 90%; +} +H1 { + text-align: center; + font-size: 160%; +} +H2 { + font-size: 120%; +} +H3 { + font-size: 100%; +} +CAPTION { font-weight: bold } +DIV.qindex { + width: 100%; + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 140%; +} +DIV.nav { + width: 100%; + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + padding: 2px; + line-height: 140%; +} +DIV.navtab { + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} +TD.navtab { + font-size: 70%; +} +A.qindex { + text-decoration: none; + font-weight: bold; + color: #1A419D; +} +A.qindex:visited { + text-decoration: none; + font-weight: bold; + color: #1A419D +} +A.qindex:hover { + text-decoration: none; + background-color: #ddddff; +} +A.qindexHL { + text-decoration: none; + font-weight: bold; + background-color: #6666cc; + color: #ffffff; + border: 1px double #9295C2; +} +A.qindexHL:hover { + text-decoration: none; + background-color: #6666cc; + color: #ffffff; +} +A.qindexHL:visited { text-decoration: none; background-color: #6666cc; color: #ffffff } +A.el { text-decoration: none; font-weight: bold } +A.elRef { font-weight: bold } +A.code:link { text-decoration: none; font-weight: normal; color: #0000FF} +A.code:visited { text-decoration: none; font-weight: normal; color: #0000FF} +A.codeRef:link { font-weight: normal; color: #0000FF} +A.codeRef:visited { font-weight: normal; color: #0000FF} +A:hover { text-decoration: none; background-color: #f2f2ff } +DL.el { margin-left: -1cm } +.fragment { + font-family: monospace, fixed; + font-size: 95%; +} +PRE.fragment { + border: 1px solid #CCCCCC; + background-color: #f5f5f5; + margin-top: 4px; + margin-bottom: 4px; + margin-left: 2px; + margin-right: 8px; + padding-left: 6px; + padding-right: 6px; + padding-top: 4px; + padding-bottom: 4px; +} +DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px } + +DIV.groupHeader { + margin-left: 16px; + margin-top: 12px; + margin-bottom: 6px; + font-weight: bold; +} +DIV.groupText { margin-left: 16px; font-style: italic; font-size: 90% } +BODY { + background: white; + color: black; + margin-right: 20px; + margin-left: 20px; +} +TD.indexkey { + background-color: #e8eef2; + font-weight: bold; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +TD.indexvalue { + background-color: #e8eef2; + font-style: italic; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px; + border: 1px solid #CCCCCC; +} +TR.memlist { + background-color: #f0f0f0; +} +P.formulaDsp { text-align: center; } +IMG.formulaDsp { } +IMG.formulaInl { vertical-align: middle; } +SPAN.keyword { color: #008000 } +SPAN.keywordtype { color: #604020 } +SPAN.keywordflow { color: #e08000 } +SPAN.comment { color: #800000 } +SPAN.preprocessor { color: #806020 } +SPAN.stringliteral { color: #002080 } +SPAN.charliteral { color: #008080 } +.mdescLeft { + padding: 0px 8px 4px 8px; + font-size: 80%; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.mdescRight { + padding: 0px 8px 4px 8px; + font-size: 80%; + font-style: italic; + background-color: #FAFAFA; + border-top: 1px none #E0E0E0; + border-right: 1px none #E0E0E0; + border-bottom: 1px none #E0E0E0; + border-left: 1px none #E0E0E0; + margin: 0px; +} +.memItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplItemLeft { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplItemRight { + padding: 1px 8px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: none; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + background-color: #FAFAFA; + font-size: 80%; +} +.memTemplParams { + padding: 1px 0px 0px 8px; + margin: 4px; + border-top-width: 1px; + border-right-width: 1px; + border-bottom-width: 1px; + border-left-width: 1px; + border-top-color: #E0E0E0; + border-right-color: #E0E0E0; + border-bottom-color: #E0E0E0; + border-left-color: #E0E0E0; + border-top-style: solid; + border-right-style: none; + border-bottom-style: none; + border-left-style: none; + color: #606060; + background-color: #FAFAFA; + font-size: 80%; +} +.search { color: #003399; + font-weight: bold; +} +FORM.search { + margin-bottom: 0px; + margin-top: 0px; +} +INPUT.search { font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +TD.tiny { font-size: 75%; +} +a { + color: #1A41A8; +} +a:visited { + color: #2A3798; +} +.dirtab { padding: 4px; + border-collapse: collapse; + border: 1px solid #84b0c7; +} +TH.dirtab { background: #e8eef2; + font-weight: bold; +} +HR { height: 1px; + border: none; + border-top: 1px solid black; +} + +/* Style for detailed member documentation */ +.memtemplate { + font-size: 80%; + color: #606060; + font-weight: normal; +} +.memnav { + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} +.memitem { + padding: 4px; + background-color: #eef3f5; + border-width: 1px; + border-style: solid; + border-color: #dedeee; + -moz-border-radius: 8px 8px 8px 8px; +} +.memname { + white-space: nowrap; + font-weight: bold; +} +.memdoc{ + padding-left: 10px; +} +.memproto { + background-color: #d5e1e8; + width: 100%; + border-width: 1px; + border-style: solid; + border-color: #84b0c7; + font-weight: bold; + -moz-border-radius: 8px 8px 8px 8px; +} +.paramkey { + text-align: right; +} +.paramtype { + white-space: nowrap; +} +.paramname { + color: #602020; + font-style: italic; +} +/* End Styling for detailed member documentation */ + +/* for the tree view */ +.ftvtree { + font-family: sans-serif; + margin:0.5em; +} +.directory { font-size: 9pt; font-weight: bold; } +.directory h3 { margin: 0px; margin-top: 1em; font-size: 11pt; } +.directory > h3 { margin-top: 0; } +.directory p { margin: 0px; white-space: nowrap; } +.directory div { display: none; margin: 0px; } +.directory img { vertical-align: -30%; } + diff --git a/drivers/usb/host/dwc_otg/doc/html/dummy__audio_8c-source.html b/drivers/usb/host/dwc_otg/doc/html/dummy__audio_8c-source.html new file mode 100644 index 000000000000..061802dd818a --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dummy__audio_8c-source.html @@ -0,0 +1,1550 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dummy_audio.c Source File + + + + + + +

dummy_audio.c

00001 /*
+00002  * zero.c -- Gadget Zero, for USB development
+00003  *
+00004  * Copyright (C) 2003-2004 David Brownell
+00005  * All rights reserved.
+00006  *
+00007  * Redistribution and use in source and binary forms, with or without
+00008  * modification, are permitted provided that the following conditions
+00009  * are met:
+00010  * 1. Redistributions of source code must retain the above copyright
+00011  *    notice, this list of conditions, and the following disclaimer,
+00012  *    without modification.
+00013  * 2. Redistributions in binary form must reproduce the above copyright
+00014  *    notice, this list of conditions and the following disclaimer in the
+00015  *    documentation and/or other materials provided with the distribution.
+00016  * 3. The names of the above-listed copyright holders may not be used
+00017  *    to endorse or promote products derived from this software without
+00018  *    specific prior written permission.
+00019  *
+00020  * ALTERNATIVELY, this software may be distributed under the terms of the
+00021  * GNU General Public License ("GPL") as published by the Free Software
+00022  * Foundation, either version 2 of that License or (at your option) any
+00023  * later version.
+00024  *
+00025  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+00026  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+00027  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+00028  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+00029  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+00030  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+00031  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+00032  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+00033  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+00034  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+00035  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+00036  */
+00037 
+00038 
+00039 /*
+00040  * Gadget Zero only needs two bulk endpoints, and is an example of how you
+00041  * can write a hardware-agnostic gadget driver running inside a USB device.
+00042  *
+00043  * Hardware details are visible (see CONFIG_USB_ZERO_* below) but don't
+00044  * affect most of the driver.
+00045  *
+00046  * Use it with the Linux host/master side "usbtest" driver to get a basic
+00047  * functional test of your device-side usb stack, or with "usb-skeleton".
+00048  *
+00049  * It supports two similar configurations.  One sinks whatever the usb host
+00050  * writes, and in return sources zeroes.  The other loops whatever the host
+00051  * writes back, so the host can read it.  Module options include:
+00052  *
+00053  *   buflen=N           default N=4096, buffer size used
+00054  *   qlen=N             default N=32, how many buffers in the loopback queue
+00055  *   loopdefault        default false, list loopback config first
+00056  *
+00057  * Many drivers will only have one configuration, letting them be much
+00058  * simpler if they also don't support high speed operation (like this
+00059  * driver does).
+00060  */
+00061 
+00062 #include <linux/config.h>
+00063 #include <linux/module.h>
+00064 #include <linux/kernel.h>
+00065 #include <linux/delay.h>
+00066 #include <linux/ioport.h>
+00067 #include <linux/sched.h>
+00068 #include <linux/slab.h>
+00069 #include <linux/smp_lock.h>
+00070 #include <linux/errno.h>
+00071 #include <linux/init.h>
+00072 #include <linux/timer.h>
+00073 #include <linux/list.h>
+00074 #include <linux/interrupt.h>
+00075 #include <linux/uts.h>
+00076 #include <linux/version.h>
+00077 #include <linux/device.h>
+00078 #include <linux/moduleparam.h>
+00079 #include <linux/proc_fs.h>
+00080 
+00081 #include <asm/byteorder.h>
+00082 #include <asm/io.h>
+00083 #include <asm/irq.h>
+00084 #include <asm/system.h>
+00085 #include <asm/unaligned.h>
+00086 
+00087 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
+00088 # include <linux/usb/ch9.h>
+00089 #else
+00090 # include <linux/usb_ch9.h>
+00091 #endif
+00092 
+00093 #include <linux/usb_gadget.h>
+00094 
+00095 
+00096 /*-------------------------------------------------------------------------*/
+00097 /*-------------------------------------------------------------------------*/
+00098 
+00099 
+00100 static int utf8_to_utf16le(const char *s, u16 *cp, unsigned len)
+00101 {
+00102         int     count = 0;
+00103         u8      c;
+00104         u16     uchar;
+00105 
+00106         /* this insists on correct encodings, though not minimal ones.
+00107          * BUT it currently rejects legit 4-byte UTF-8 code points,
+00108          * which need surrogate pairs.  (Unicode 3.1 can use them.)
+00109          */
+00110         while (len != 0 && (c = (u8) *s++) != 0) {
+00111                 if (unlikely(c & 0x80)) {
+00112                         // 2-byte sequence:
+00113                         // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
+00114                         if ((c & 0xe0) == 0xc0) {
+00115                                 uchar = (c & 0x1f) << 6;
+00116 
+00117                                 c = (u8) *s++;
+00118                                 if ((c & 0xc0) != 0xc0)
+00119                                         goto fail;
+00120                                 c &= 0x3f;
+00121                                 uchar |= c;
+00122 
+00123                         // 3-byte sequence (most CJKV characters):
+00124                         // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
+00125                         } else if ((c & 0xf0) == 0xe0) {
+00126                                 uchar = (c & 0x0f) << 12;
+00127 
+00128                                 c = (u8) *s++;
+00129                                 if ((c & 0xc0) != 0xc0)
+00130                                         goto fail;
+00131                                 c &= 0x3f;
+00132                                 uchar |= c << 6;
+00133 
+00134                                 c = (u8) *s++;
+00135                                 if ((c & 0xc0) != 0xc0)
+00136                                         goto fail;
+00137                                 c &= 0x3f;
+00138                                 uchar |= c;
+00139 
+00140                                 /* no bogus surrogates */
+00141                                 if (0xd800 <= uchar && uchar <= 0xdfff)
+00142                                         goto fail;
+00143 
+00144                         // 4-byte sequence (surrogate pairs, currently rare):
+00145                         // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
+00146                         //     = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
+00147                         // (uuuuu = wwww + 1)
+00148                         // FIXME accept the surrogate code points (only)
+00149 
+00150                         } else
+00151                                 goto fail;
+00152                 } else
+00153                         uchar = c;
+00154                 put_unaligned (cpu_to_le16 (uchar), cp++);
+00155                 count++;
+00156                 len--;
+00157         }
+00158         return count;
+00159 fail:
+00160         return -1;
+00161 }
+00162 
+00163 
+00181 int
+00182 usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
+00183 {
+00184         struct usb_string       *s;
+00185         int                     len;
+00186 
+00187         /* descriptor 0 has the language id */
+00188         if (id == 0) {
+00189                 buf [0] = 4;
+00190                 buf [1] = USB_DT_STRING;
+00191                 buf [2] = (u8) table->language;
+00192                 buf [3] = (u8) (table->language >> 8);
+00193                 return 4;
+00194         }
+00195         for (s = table->strings; s && s->s; s++)
+00196                 if (s->id == id)
+00197                         break;
+00198 
+00199         /* unrecognized: stall. */
+00200         if (!s || !s->s)
+00201                 return -EINVAL;
+00202 
+00203         /* string descriptors have length, tag, then UTF16-LE text */
+00204         len = min ((size_t) 126, strlen (s->s));
+00205         memset (buf + 2, 0, 2 * len);   /* zero all the bytes */
+00206         len = utf8_to_utf16le(s->s, (u16 *)&buf[2], len);
+00207         if (len < 0)
+00208                 return -EINVAL;
+00209         buf [0] = (len + 1) * 2;
+00210         buf [1] = USB_DT_STRING;
+00211         return buf [0];
+00212 }
+00213 
+00214 
+00215 /*-------------------------------------------------------------------------*/
+00216 /*-------------------------------------------------------------------------*/
+00217 
+00218 
+00231 int
+00232 usb_descriptor_fillbuf(void *buf, unsigned buflen,
+00233                 const struct usb_descriptor_header **src)
+00234 {
+00235         u8      *dest = buf;
+00236 
+00237         if (!src)
+00238                 return -EINVAL;
+00239 
+00240         /* fill buffer from src[] until null descriptor ptr */
+00241         for (; 0 != *src; src++) {
+00242                 unsigned                len = (*src)->bLength;
+00243 
+00244                 if (len > buflen)
+00245                         return -EINVAL;
+00246                 memcpy(dest, *src, len);
+00247                 buflen -= len;
+00248                 dest += len;
+00249         }
+00250         return dest - (u8 *)buf;
+00251 }
+00252 
+00253 
+00274 int usb_gadget_config_buf(
+00275         const struct usb_config_descriptor      *config,
+00276         void                                    *buf,
+00277         unsigned                                length,
+00278         const struct usb_descriptor_header      **desc
+00279 )
+00280 {
+00281         struct usb_config_descriptor            *cp = buf;
+00282         int                                     len;
+00283 
+00284         /* config descriptor first */
+00285         if (length < USB_DT_CONFIG_SIZE || !desc)
+00286                 return -EINVAL;
+00287         *cp = *config; 
+00288 
+00289         /* then interface/endpoint/class/vendor/... */
+00290         len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
+00291                         length - USB_DT_CONFIG_SIZE, desc);
+00292         if (len < 0)
+00293                 return len;
+00294         len += USB_DT_CONFIG_SIZE;
+00295         if (len > 0xffff)
+00296                 return -EINVAL;
+00297 
+00298         /* patch up the config descriptor */
+00299         cp->bLength = USB_DT_CONFIG_SIZE;
+00300         cp->bDescriptorType = USB_DT_CONFIG;
+00301         cp->wTotalLength = cpu_to_le16(len);
+00302         cp->bmAttributes |= USB_CONFIG_ATT_ONE;
+00303         return len;
+00304 }
+00305 
+00306 /*-------------------------------------------------------------------------*/
+00307 /*-------------------------------------------------------------------------*/
+00308 
+00309 
+00310 #define RBUF_LEN (1024*1024)
+00311 static int rbuf_start;
+00312 static int rbuf_len;
+00313 static __u8 rbuf[RBUF_LEN];
+00314 
+00315 /*-------------------------------------------------------------------------*/
+00316 
+00317 #define DRIVER_VERSION          "St Patrick's Day 2004"
+00318 
+00319 static const char shortname [] = "zero";
+00320 static const char longname [] = "YAMAHA YST-MS35D USB Speaker  ";
+00321 
+00322 static const char source_sink [] = "source and sink data";
+00323 static const char loopback [] = "loop input to output";
+00324 
+00325 /*-------------------------------------------------------------------------*/
+00326 
+00327 /*
+00328  * driver assumes self-powered hardware, and
+00329  * has no way for users to trigger remote wakeup.
+00330  *
+00331  * this version autoconfigures as much as possible,
+00332  * which is reasonable for most "bulk-only" drivers.
+00333  */
+00334 static const char *EP_IN_NAME;          /* source */
+00335 static const char *EP_OUT_NAME;         /* sink */
+00336 
+00337 /*-------------------------------------------------------------------------*/
+00338 
+00339 /* big enough to hold our biggest descriptor */
+00340 #define USB_BUFSIZ      512
+00341 
+00342 struct zero_dev {
+00343         spinlock_t              lock;
+00344         struct usb_gadget       *gadget;
+00345         struct usb_request      *req;           /* for control responses */
+00346 
+00347         /* when configured, we have one of two configs:
+00348          * - source data (in to host) and sink it (out from host)
+00349          * - or loop it back (out from host back in to host)
+00350          */
+00351         u8                      config;
+00352         struct usb_ep           *in_ep, *out_ep;
+00353 
+00354         /* autoresume timer */
+00355         struct timer_list       resume;
+00356 };
+00357 
+00358 #define xprintk(d,level,fmt,args...) \
+00359         dev_printk(level , &(d)->gadget->dev , fmt , ## args)
+00360 
+00361 #ifdef DEBUG
+00362 #define DBG(dev,fmt,args...) \
+00363         xprintk(dev , KERN_DEBUG , fmt , ## args)
+00364 #else
+00365 #define DBG(dev,fmt,args...) \
+00366         do { } while (0)
+00367 #endif /* DEBUG */
+00368 
+00369 #ifdef VERBOSE
+00370 #define VDBG    DBG
+00371 #else
+00372 #define VDBG(dev,fmt,args...) \
+00373         do { } while (0)
+00374 #endif /* VERBOSE */
+00375 
+00376 #define ERROR(dev,fmt,args...) \
+00377         xprintk(dev , KERN_ERR , fmt , ## args)
+00378 #define WARN(dev,fmt,args...) \
+00379         xprintk(dev , KERN_WARNING , fmt , ## args)
+00380 #define INFO(dev,fmt,args...) \
+00381         xprintk(dev , KERN_INFO , fmt , ## args)
+00382 
+00383 /*-------------------------------------------------------------------------*/
+00384 
+00385 static unsigned buflen = 4096;
+00386 static unsigned qlen = 32;
+00387 static unsigned pattern = 0;
+00388 
+00389 module_param (buflen, uint, S_IRUGO|S_IWUSR);
+00390 module_param (qlen, uint, S_IRUGO|S_IWUSR);
+00391 module_param (pattern, uint, S_IRUGO|S_IWUSR);
+00392 
+00393 /*
+00394  * if it's nonzero, autoresume says how many seconds to wait
+00395  * before trying to wake up the host after suspend.
+00396  */
+00397 static unsigned autoresume = 0;
+00398 module_param (autoresume, uint, 0);
+00399 
+00400 /*
+00401  * Normally the "loopback" configuration is second (index 1) so
+00402  * it's not the default.  Here's where to change that order, to
+00403  * work better with hosts where config changes are problematic.
+00404  * Or controllers (like superh) that only support one config.
+00405  */
+00406 static int loopdefault = 0;
+00407 
+00408 module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
+00409 
+00410 /*-------------------------------------------------------------------------*/
+00411 
+00412 /* Thanks to NetChip Technologies for donating this product ID.
+00413  *
+00414  * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
+00415  * Instead:  allocate your own, using normal USB-IF procedures.
+00416  */
+00417 #ifndef CONFIG_USB_ZERO_HNPTEST
+00418 #define DRIVER_VENDOR_NUM       0x0525          /* NetChip */
+00419 #define DRIVER_PRODUCT_NUM      0xa4a0          /* Linux-USB "Gadget Zero" */
+00420 #else
+00421 #define DRIVER_VENDOR_NUM       0x1a0a          /* OTG test device IDs */
+00422 #define DRIVER_PRODUCT_NUM      0xbadd
+00423 #endif
+00424 
+00425 /*-------------------------------------------------------------------------*/
+00426 
+00427 /*
+00428  * DESCRIPTORS ... most are static, but strings and (full)
+00429  * configuration descriptors are built on demand.
+00430  */
+00431 
+00432 /*
+00433 #define STRING_MANUFACTURER             25
+00434 #define STRING_PRODUCT                  42
+00435 #define STRING_SERIAL                   101
+00436 */
+00437 #define STRING_MANUFACTURER             1
+00438 #define STRING_PRODUCT                  2
+00439 #define STRING_SERIAL                   3
+00440 
+00441 #define STRING_SOURCE_SINK              250
+00442 #define STRING_LOOPBACK                 251
+00443 
+00444 /*
+00445  * This device advertises two configurations; these numbers work
+00446  * on a pxa250 as well as more flexible hardware.
+00447  */
+00448 #define CONFIG_SOURCE_SINK      3
+00449 #define CONFIG_LOOPBACK         2
+00450 
+00451 /*
+00452 static struct usb_device_descriptor
+00453 device_desc = {
+00454         .bLength =              sizeof device_desc,
+00455         .bDescriptorType =      USB_DT_DEVICE,
+00456 
+00457         .bcdUSB =               __constant_cpu_to_le16 (0x0200),
+00458         .bDeviceClass =         USB_CLASS_VENDOR_SPEC,
+00459 
+00460         .idVendor =             __constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
+00461         .idProduct =            __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
+00462         .iManufacturer =        STRING_MANUFACTURER,
+00463         .iProduct =             STRING_PRODUCT,
+00464         .iSerialNumber =        STRING_SERIAL,
+00465         .bNumConfigurations =   2,
+00466 };
+00467 */
+00468 static struct usb_device_descriptor
+00469 device_desc = {
+00470         .bLength =              sizeof device_desc,
+00471         .bDescriptorType =      USB_DT_DEVICE,
+00472         .bcdUSB =               __constant_cpu_to_le16 (0x0100),
+00473         .bDeviceClass =         USB_CLASS_PER_INTERFACE,
+00474         .bDeviceSubClass =      0,
+00475         .bDeviceProtocol =      0,
+00476         .bMaxPacketSize0 =      64,
+00477         .bcdDevice =            __constant_cpu_to_le16 (0x0100),
+00478         .idVendor =             __constant_cpu_to_le16 (0x0499),
+00479         .idProduct =            __constant_cpu_to_le16 (0x3002),
+00480         .iManufacturer =        STRING_MANUFACTURER,
+00481         .iProduct =             STRING_PRODUCT,
+00482         .iSerialNumber =        STRING_SERIAL,
+00483         .bNumConfigurations =   1,
+00484 };
+00485 
+00486 static struct usb_config_descriptor
+00487 z_config = {
+00488         .bLength =              sizeof z_config,
+00489         .bDescriptorType =      USB_DT_CONFIG,
+00490 
+00491         /* compute wTotalLength on the fly */
+00492         .bNumInterfaces =       2,
+00493         .bConfigurationValue =  1,
+00494         .iConfiguration =       0,
+00495         .bmAttributes =         0x40,
+00496         .bMaxPower =            0,      /* self-powered */
+00497 };
+00498 
+00499 
+00500 static struct usb_otg_descriptor
+00501 otg_descriptor = {
+00502         .bLength =              sizeof otg_descriptor,
+00503         .bDescriptorType =      USB_DT_OTG,
+00504 
+00505         .bmAttributes =         USB_OTG_SRP,
+00506 };
+00507 
+00508 /* one interface in each configuration */
+00509 #ifdef  CONFIG_USB_GADGET_DUALSPEED
+00510 
+00511 /*
+00512  * usb 2.0 devices need to expose both high speed and full speed
+00513  * descriptors, unless they only run at full speed.
+00514  *
+00515  * that means alternate endpoint descriptors (bigger packets)
+00516  * and a "device qualifier" ... plus more construction options
+00517  * for the config descriptor.
+00518  */
+00519 
+00520 static struct usb_qualifier_descriptor
+00521 dev_qualifier = {
+00522         .bLength =              sizeof dev_qualifier,
+00523         .bDescriptorType =      USB_DT_DEVICE_QUALIFIER,
+00524 
+00525         .bcdUSB =               __constant_cpu_to_le16 (0x0200),
+00526         .bDeviceClass =         USB_CLASS_VENDOR_SPEC,
+00527 
+00528         .bNumConfigurations =   2,
+00529 };
+00530 
+00531 
+00532 struct usb_cs_as_general_descriptor {
+00533         __u8  bLength;
+00534         __u8  bDescriptorType;
+00535 
+00536         __u8  bDescriptorSubType;
+00537         __u8  bTerminalLink;
+00538         __u8  bDelay;
+00539         __u16  wFormatTag;
+00540 } __attribute__ ((packed));
+00541 
+00542 struct usb_cs_as_format_descriptor {
+00543         __u8  bLength;
+00544         __u8  bDescriptorType;
+00545 
+00546         __u8  bDescriptorSubType;
+00547         __u8  bFormatType;
+00548         __u8  bNrChannels;
+00549         __u8  bSubframeSize;
+00550         __u8  bBitResolution;
+00551         __u8  bSamfreqType;
+00552         __u8  tLowerSamFreq[3];
+00553         __u8  tUpperSamFreq[3];
+00554 } __attribute__ ((packed));
+00555 
+00556 static const struct usb_interface_descriptor
+00557 z_audio_control_if_desc = {
+00558         .bLength =              sizeof z_audio_control_if_desc,
+00559         .bDescriptorType =      USB_DT_INTERFACE,
+00560         .bInterfaceNumber = 0,
+00561         .bAlternateSetting = 0,
+00562         .bNumEndpoints = 0,
+00563         .bInterfaceClass = USB_CLASS_AUDIO,
+00564         .bInterfaceSubClass = 0x1,
+00565         .bInterfaceProtocol = 0,
+00566         .iInterface = 0,
+00567 };
+00568 
+00569 static const struct usb_interface_descriptor
+00570 z_audio_if_desc = {
+00571         .bLength =              sizeof z_audio_if_desc,
+00572         .bDescriptorType =      USB_DT_INTERFACE,
+00573         .bInterfaceNumber = 1,
+00574         .bAlternateSetting = 0,
+00575         .bNumEndpoints = 0,
+00576         .bInterfaceClass = USB_CLASS_AUDIO,
+00577         .bInterfaceSubClass = 0x2,
+00578         .bInterfaceProtocol = 0,
+00579         .iInterface = 0,
+00580 };
+00581 
+00582 static const struct usb_interface_descriptor
+00583 z_audio_if_desc2 = {
+00584         .bLength =              sizeof z_audio_if_desc,
+00585         .bDescriptorType =      USB_DT_INTERFACE,
+00586         .bInterfaceNumber = 1,
+00587         .bAlternateSetting = 1,
+00588         .bNumEndpoints = 1,
+00589         .bInterfaceClass = USB_CLASS_AUDIO,
+00590         .bInterfaceSubClass = 0x2,
+00591         .bInterfaceProtocol = 0,
+00592         .iInterface = 0,
+00593 };
+00594 
+00595 static const struct usb_cs_as_general_descriptor
+00596 z_audio_cs_as_if_desc = {
+00597         .bLength = 7,
+00598         .bDescriptorType = 0x24,
+00599         
+00600         .bDescriptorSubType = 0x01,
+00601         .bTerminalLink = 0x01,
+00602         .bDelay = 0x0,
+00603         .wFormatTag = __constant_cpu_to_le16 (0x0001)
+00604 };
+00605 
+00606 
+00607 static const struct usb_cs_as_format_descriptor 
+00608 z_audio_cs_as_format_desc = {
+00609         .bLength = 0xe,
+00610         .bDescriptorType = 0x24,
+00611         
+00612         .bDescriptorSubType = 2,
+00613         .bFormatType = 1,
+00614         .bNrChannels = 1,
+00615         .bSubframeSize = 1,
+00616         .bBitResolution = 8,
+00617         .bSamfreqType = 0,
+00618         .tLowerSamFreq = {0x7e, 0x13, 0x00},
+00619         .tUpperSamFreq = {0xe2, 0xd6, 0x00},
+00620 };
+00621 
+00622 static const struct usb_endpoint_descriptor 
+00623 z_iso_ep = {
+00624         .bLength = 0x09,
+00625         .bDescriptorType = 0x05,
+00626         .bEndpointAddress = 0x04,
+00627         .bmAttributes = 0x09,
+00628         .wMaxPacketSize = 0x0038,
+00629         .bInterval = 0x01,
+00630         .bRefresh = 0x00,
+00631         .bSynchAddress = 0x00,  
+00632 };
+00633 
+00634 static char z_iso_ep2[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
+00635 
+00636 // 9 bytes
+00637 static char z_ac_interface_header_desc[] = 
+00638 { 0x09, 0x24, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x01, 0x01 };
+00639 
+00640 // 12 bytes
+00641 static char z_0[] = {0x0c, 0x24, 0x02, 0x01, 0x01, 0x01, 0x00, 0x02, 
+00642                      0x03, 0x00, 0x00, 0x00};
+00643 // 13 bytes
+00644 static char z_1[] = {0x0d, 0x24, 0x06, 0x02, 0x01, 0x02, 0x15, 0x00, 
+00645                      0x02, 0x00, 0x02, 0x00, 0x00};
+00646 // 9 bytes
+00647 static char z_2[] = {0x09, 0x24, 0x03, 0x03, 0x01, 0x03, 0x00, 0x02, 
+00648                      0x00};
+00649 
+00650 static char za_0[] = {0x09, 0x04, 0x01, 0x02, 0x01, 0x01, 0x02, 0x00, 
+00651                       0x00};
+00652 
+00653 static char za_1[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
+00654 
+00655 static char za_2[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x01, 0x08, 0x00, 
+00656                       0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
+00657 
+00658 static char za_3[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00,
+00659                       0x00};
+00660 
+00661 static char za_4[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
+00662 
+00663 static char za_5[] = {0x09, 0x04, 0x01, 0x03, 0x01, 0x01, 0x02, 0x00,
+00664                       0x00};
+00665 
+00666 static char za_6[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
+00667 
+00668 static char za_7[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x00,
+00669                       0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
+00670 
+00671 static char za_8[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00,
+00672                       0x00};
+00673 
+00674 static char za_9[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
+00675 
+00676 static char za_10[] = {0x09, 0x04, 0x01, 0x04, 0x01, 0x01, 0x02, 0x00,
+00677                        0x00};
+00678 
+00679 static char za_11[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
+00680 
+00681 static char za_12[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x00,
+00682                        0x73, 0x13, 0x00, 0xe2, 0xd6, 0x00};
+00683 
+00684 static char za_13[] = {0x09, 0x05, 0x04, 0x09, 0xe0, 0x00, 0x01, 0x00,
+00685                        0x00};
+00686 
+00687 static char za_14[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
+00688 
+00689 static char za_15[] = {0x09, 0x04, 0x01, 0x05, 0x01, 0x01, 0x02, 0x00, 
+00690                        0x00};
+00691 
+00692 static char za_16[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
+00693 
+00694 static char za_17[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x03, 0x14, 0x00, 
+00695                        0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
+00696 
+00697 static char za_18[] = {0x09, 0x05, 0x04, 0x09, 0xa8, 0x00, 0x01, 0x00,
+00698                        0x00};
+00699 
+00700 static char za_19[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
+00701 
+00702 static char za_20[] = {0x09, 0x04, 0x01, 0x06, 0x01, 0x01, 0x02, 0x00,
+00703                        0x00};
+00704 
+00705 static char za_21[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00};
+00706 
+00707 static char za_22[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x03, 0x14, 0x00, 
+00708                        0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00};
+00709 
+00710 static char za_23[] = {0x09, 0x05, 0x04, 0x09, 0x50, 0x01, 0x01, 0x00,
+00711                        0x00};
+00712 
+00713 static char za_24[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02};
+00714 
+00715 
+00716 
+00717 static const struct usb_descriptor_header *z_function [] = {
+00718         (struct usb_descriptor_header *) &z_audio_control_if_desc,
+00719         (struct usb_descriptor_header *) &z_ac_interface_header_desc,
+00720         (struct usb_descriptor_header *) &z_0,
+00721         (struct usb_descriptor_header *) &z_1,
+00722         (struct usb_descriptor_header *) &z_2,
+00723         (struct usb_descriptor_header *) &z_audio_if_desc,
+00724         (struct usb_descriptor_header *) &z_audio_if_desc2,
+00725         (struct usb_descriptor_header *) &z_audio_cs_as_if_desc,
+00726         (struct usb_descriptor_header *) &z_audio_cs_as_format_desc,
+00727         (struct usb_descriptor_header *) &z_iso_ep,
+00728         (struct usb_descriptor_header *) &z_iso_ep2,
+00729         (struct usb_descriptor_header *) &za_0,
+00730         (struct usb_descriptor_header *) &za_1,
+00731         (struct usb_descriptor_header *) &za_2,
+00732         (struct usb_descriptor_header *) &za_3,
+00733         (struct usb_descriptor_header *) &za_4,
+00734         (struct usb_descriptor_header *) &za_5,
+00735         (struct usb_descriptor_header *) &za_6,
+00736         (struct usb_descriptor_header *) &za_7,
+00737         (struct usb_descriptor_header *) &za_8,
+00738         (struct usb_descriptor_header *) &za_9,
+00739         (struct usb_descriptor_header *) &za_10,
+00740         (struct usb_descriptor_header *) &za_11,
+00741         (struct usb_descriptor_header *) &za_12,
+00742         (struct usb_descriptor_header *) &za_13,
+00743         (struct usb_descriptor_header *) &za_14,
+00744         (struct usb_descriptor_header *) &za_15,
+00745         (struct usb_descriptor_header *) &za_16,
+00746         (struct usb_descriptor_header *) &za_17,
+00747         (struct usb_descriptor_header *) &za_18,
+00748         (struct usb_descriptor_header *) &za_19,
+00749         (struct usb_descriptor_header *) &za_20,
+00750         (struct usb_descriptor_header *) &za_21,
+00751         (struct usb_descriptor_header *) &za_22,
+00752         (struct usb_descriptor_header *) &za_23,
+00753         (struct usb_descriptor_header *) &za_24,
+00754         NULL,
+00755 };
+00756 
+00757 /* maxpacket and other transfer characteristics vary by speed. */
+00758 #define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
+00759 
+00760 #else
+00761 
+00762 /* if there's no high speed support, maxpacket doesn't change. */
+00763 #define ep_desc(g,hs,fs) fs
+00764 
+00765 #endif  /* !CONFIG_USB_GADGET_DUALSPEED */
+00766 
+00767 static char                             manufacturer [40];
+00768 //static char                           serial [40];
+00769 static char                             serial [] = "Ser 00 em";
+00770 
+00771 /* static strings, in UTF-8 */
+00772 static struct usb_string                strings [] = {
+00773         { STRING_MANUFACTURER, manufacturer, },
+00774         { STRING_PRODUCT, longname, },
+00775         { STRING_SERIAL, serial, },
+00776         { STRING_LOOPBACK, loopback, },
+00777         { STRING_SOURCE_SINK, source_sink, },
+00778         {  }                    /* end of list */
+00779 };
+00780 
+00781 static struct usb_gadget_strings        stringtab = {
+00782         .language       = 0x0409,       /* en-us */
+00783         .strings        = strings,
+00784 };
+00785 
+00786 /*
+00787  * config descriptors are also handcrafted.  these must agree with code
+00788  * that sets configurations, and with code managing interfaces and their
+00789  * altsettings.  other complexity may come from:
+00790  *
+00791  *  - high speed support, including "other speed config" rules
+00792  *  - multiple configurations
+00793  *  - interfaces with alternate settings
+00794  *  - embedded class or vendor-specific descriptors
+00795  *
+00796  * this handles high speed, and has a second config that could as easily
+00797  * have been an alternate interface setting (on most hardware).
+00798  *
+00799  * NOTE:  to demonstrate (and test) more USB capabilities, this driver
+00800  * should include an altsetting to test interrupt transfers, including
+00801  * high bandwidth modes at high speed.  (Maybe work like Intel's test
+00802  * device?)
+00803  */
+00804 static int
+00805 config_buf (struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index)
+00806 {
+00807         int len;
+00808         const struct usb_descriptor_header **function;
+00809         
+00810         function = z_function;
+00811         len = usb_gadget_config_buf (&z_config, buf, USB_BUFSIZ, function);
+00812         if (len < 0)
+00813                 return len;
+00814         ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
+00815         return len;
+00816 }
+00817 
+00818 /*-------------------------------------------------------------------------*/
+00819 
+00820 static struct usb_request *
+00821 alloc_ep_req (struct usb_ep *ep, unsigned length)
+00822 {
+00823         struct usb_request      *req;
+00824 
+00825         req = usb_ep_alloc_request (ep, GFP_ATOMIC);
+00826         if (req) {
+00827                 req->length = length;
+00828                 req->buf = usb_ep_alloc_buffer (ep, length,
+00829                                 &req->dma, GFP_ATOMIC);
+00830                 if (!req->buf) {
+00831                         usb_ep_free_request (ep, req);
+00832                         req = NULL;
+00833                 }
+00834         }
+00835         return req;
+00836 }
+00837 
+00838 static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
+00839 {
+00840         if (req->buf)
+00841                 usb_ep_free_buffer (ep, req->buf, req->dma, req->length);
+00842         usb_ep_free_request (ep, req);
+00843 }
+00844 
+00845 /*-------------------------------------------------------------------------*/
+00846 
+00847 /* optionally require specific source/sink data patterns  */
+00848 
+00849 static int
+00850 check_read_data (
+00851         struct zero_dev         *dev,
+00852         struct usb_ep           *ep,
+00853         struct usb_request      *req
+00854 )
+00855 {
+00856         unsigned        i;
+00857         u8              *buf = req->buf;
+00858 
+00859         for (i = 0; i < req->actual; i++, buf++) {
+00860                 switch (pattern) {
+00861                 /* all-zeroes has no synchronization issues */
+00862                 case 0:
+00863                         if (*buf == 0)
+00864                                 continue;
+00865                         break;
+00866                 /* mod63 stays in sync with short-terminated transfers,
+00867                  * or otherwise when host and gadget agree on how large
+00868                  * each usb transfer request should be.  resync is done
+00869                  * with set_interface or set_config.
+00870                  */
+00871                 case 1:
+00872                         if (*buf == (u8)(i % 63))
+00873                                 continue;
+00874                         break;
+00875                 }
+00876                 ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf);
+00877                 usb_ep_set_halt (ep);
+00878                 return -EINVAL;
+00879         }
+00880         return 0;
+00881 }
+00882 
+00883 /*-------------------------------------------------------------------------*/
+00884 
+00885 static void zero_reset_config (struct zero_dev *dev)
+00886 {
+00887         if (dev->config == 0)
+00888                 return;
+00889 
+00890         DBG (dev, "reset config\n");
+00891 
+00892         /* just disable endpoints, forcing completion of pending i/o.
+00893          * all our completion handlers free their requests in this case.
+00894          */
+00895         if (dev->in_ep) {
+00896                 usb_ep_disable (dev->in_ep);
+00897                 dev->in_ep = NULL;
+00898         }
+00899         if (dev->out_ep) {
+00900                 usb_ep_disable (dev->out_ep);
+00901                 dev->out_ep = NULL;
+00902         }
+00903         dev->config = 0;
+00904         del_timer (&dev->resume);
+00905 }
+00906 
+00907 #define _write(f, buf, sz) (f->f_op->write(f, buf, sz, &f->f_pos))
+00908 
+00909 static void 
+00910 zero_isoc_complete (struct usb_ep *ep, struct usb_request *req)
+00911 {
+00912         struct zero_dev *dev = ep->driver_data;
+00913         int             status = req->status;
+00914         int i, j;
+00915 
+00916         switch (status) {
+00917 
+00918         case 0:                         /* normal completion? */
+00919                 //printk ("\nzero ---------------> isoc normal completion %d bytes\n", req->actual);
+00920                 for (i=0, j=rbuf_start; i<req->actual; i++) {
+00921                         //printk ("%02x ", ((__u8*)req->buf)[i]);
+00922                         rbuf[j] = ((__u8*)req->buf)[i];
+00923                         j++;
+00924                         if (j >= RBUF_LEN) j=0;
+00925                 }
+00926                 rbuf_start = j;
+00927                 //printk ("\n\n");
+00928 
+00929                 if (rbuf_len < RBUF_LEN) {
+00930                         rbuf_len += req->actual;
+00931                         if (rbuf_len > RBUF_LEN) {
+00932                                 rbuf_len = RBUF_LEN;
+00933                         }
+00934                 }
+00935 
+00936                 break;
+00937 
+00938         /* this endpoint is normally active while we're configured */
+00939         case -ECONNABORTED:             /* hardware forced ep reset */
+00940         case -ECONNRESET:               /* request dequeued */
+00941         case -ESHUTDOWN:                /* disconnect from host */
+00942                 VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
+00943                                 req->actual, req->length);
+00944                 if (ep == dev->out_ep)
+00945                         check_read_data (dev, ep, req);
+00946                 free_ep_req (ep, req);
+00947                 return;
+00948 
+00949         case -EOVERFLOW:                /* buffer overrun on read means that
+00950                                          * we didn't provide a big enough
+00951                                          * buffer.
+00952                                          */
+00953         default:
+00954 #if 1
+00955                 DBG (dev, "%s complete --> %d, %d/%d\n", ep->name,
+00956                                 status, req->actual, req->length);
+00957 #endif
+00958         case -EREMOTEIO:                /* short read */
+00959                 break;
+00960         }
+00961 
+00962         status = usb_ep_queue (ep, req, GFP_ATOMIC);
+00963         if (status) {
+00964                 ERROR (dev, "kill %s:  resubmit %d bytes --> %d\n",
+00965                                 ep->name, req->length, status);
+00966                 usb_ep_set_halt (ep);
+00967                 /* FIXME recover later ... somehow */
+00968         }
+00969 }
+00970 
+00971 static struct usb_request *
+00972 zero_start_isoc_ep (struct usb_ep *ep, int gfp_flags)
+00973 {
+00974         struct usb_request      *req;
+00975         int                     status;
+00976 
+00977         req = alloc_ep_req (ep, 512);
+00978         if (!req)
+00979                 return NULL;
+00980 
+00981         req->complete = zero_isoc_complete;
+00982 
+00983         status = usb_ep_queue (ep, req, gfp_flags);
+00984         if (status) {
+00985                 struct zero_dev *dev = ep->driver_data;
+00986 
+00987                 ERROR (dev, "start %s --> %d\n", ep->name, status);
+00988                 free_ep_req (ep, req);
+00989                 req = NULL;
+00990         }
+00991 
+00992         return req;
+00993 }
+00994 
+00995 /* change our operational config.  this code must agree with the code
+00996  * that returns config descriptors, and altsetting code.
+00997  *
+00998  * it's also responsible for power management interactions. some
+00999  * configurations might not work with our current power sources.
+01000  *
+01001  * note that some device controller hardware will constrain what this
+01002  * code can do, perhaps by disallowing more than one configuration or
+01003  * by limiting configuration choices (like the pxa2xx).
+01004  */
+01005 static int
+01006 zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags)
+01007 {
+01008         int                     result = 0;
+01009         struct usb_gadget       *gadget = dev->gadget;
+01010         const struct usb_endpoint_descriptor    *d;
+01011         struct usb_ep           *ep;
+01012 
+01013         if (number == dev->config)
+01014                 return 0;
+01015 
+01016         zero_reset_config (dev);
+01017 
+01018         gadget_for_each_ep (ep, gadget) {
+01019 
+01020                 if (strcmp (ep->name, "ep4") == 0) {
+01021 
+01022                         d = (struct usb_endpoint_descripter *)&za_23; // isoc ep desc for audio i/f alt setting 6
+01023                         result = usb_ep_enable (ep, d);
+01024 
+01025                         if (result == 0) {
+01026                                 ep->driver_data = dev;
+01027                                 dev->in_ep = ep;
+01028 
+01029                                 if (zero_start_isoc_ep (ep, gfp_flags) != 0) {
+01030 
+01031                                         dev->in_ep = ep;
+01032                                         continue;
+01033                                 }
+01034 
+01035                                 usb_ep_disable (ep);
+01036                                 result = -EIO;
+01037                         }
+01038                 }
+01039 
+01040         }
+01041 
+01042         dev->config = number;
+01043         return result;
+01044 }
+01045 
+01046 /*-------------------------------------------------------------------------*/
+01047 
+01048 static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
+01049 {
+01050         if (req->status || req->actual != req->length)
+01051                 DBG ((struct zero_dev *) ep->driver_data,
+01052                                 "setup complete --> %d, %d/%d\n",
+01053                                 req->status, req->actual, req->length);
+01054 }
+01055 
+01056 /*
+01057  * The setup() callback implements all the ep0 functionality that's
+01058  * not handled lower down, in hardware or the hardware driver (like
+01059  * device and endpoint feature flags, and their status).  It's all
+01060  * housekeeping for the gadget function we're implementing.  Most of
+01061  * the work is in config-specific setup.
+01062  */
+01063 static int
+01064 zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+01065 {
+01066         struct zero_dev         *dev = get_gadget_data (gadget);
+01067         struct usb_request      *req = dev->req;
+01068         int                     value = -EOPNOTSUPP;
+01069 
+01070         /* usually this stores reply data in the pre-allocated ep0 buffer,
+01071          * but config change events will reconfigure hardware.
+01072          */
+01073         req->zero = 0;
+01074         switch (ctrl->bRequest) {
+01075 
+01076         case USB_REQ_GET_DESCRIPTOR:
+01077 
+01078                 switch (ctrl->wValue >> 8) {
+01079 
+01080                 case USB_DT_DEVICE:
+01081                         value = min (ctrl->wLength, (u16) sizeof device_desc);
+01082                         memcpy (req->buf, &device_desc, value);
+01083                         break;
+01084 #ifdef CONFIG_USB_GADGET_DUALSPEED
+01085                 case USB_DT_DEVICE_QUALIFIER:
+01086                         if (!gadget->is_dualspeed)
+01087                                 break;
+01088                         value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
+01089                         memcpy (req->buf, &dev_qualifier, value);
+01090                         break;
+01091 
+01092                 case USB_DT_OTHER_SPEED_CONFIG:
+01093                         if (!gadget->is_dualspeed)
+01094                                 break;
+01095                         // FALLTHROUGH
+01096 #endif /* CONFIG_USB_GADGET_DUALSPEED */
+01097                 case USB_DT_CONFIG:
+01098                         value = config_buf (gadget, req->buf,
+01099                                         ctrl->wValue >> 8,
+01100                                         ctrl->wValue & 0xff);
+01101                         if (value >= 0)
+01102                                 value = min (ctrl->wLength, (u16) value);
+01103                         break;
+01104 
+01105                 case USB_DT_STRING:
+01106                         /* wIndex == language code.
+01107                          * this driver only handles one language, you can
+01108                          * add string tables for other languages, using
+01109                          * any UTF-8 characters
+01110                          */
+01111                         value = usb_gadget_get_string (&stringtab,
+01112                                         ctrl->wValue & 0xff, req->buf);
+01113                         if (value >= 0) {
+01114                                 value = min (ctrl->wLength, (u16) value);
+01115                         }
+01116                         break;
+01117                 }
+01118                 break;
+01119 
+01120         /* currently two configs, two speeds */
+01121         case USB_REQ_SET_CONFIGURATION:
+01122                 if (ctrl->bRequestType != 0)
+01123                         goto unknown;
+01124 
+01125                 spin_lock (&dev->lock);
+01126                 value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC);
+01127                 spin_unlock (&dev->lock);
+01128                 break;
+01129         case USB_REQ_GET_CONFIGURATION:
+01130                 if (ctrl->bRequestType != USB_DIR_IN)
+01131                         goto unknown;
+01132                 *(u8 *)req->buf = dev->config;
+01133                 value = min (ctrl->wLength, (u16) 1);
+01134                 break;
+01135 
+01136         /* until we add altsetting support, or other interfaces,
+01137          * only 0/0 are possible.  pxa2xx only supports 0/0 (poorly)
+01138          * and already killed pending endpoint I/O.
+01139          */
+01140         case USB_REQ_SET_INTERFACE:
+01141 
+01142                 if (ctrl->bRequestType != USB_RECIP_INTERFACE)
+01143                         goto unknown;
+01144                 spin_lock (&dev->lock);
+01145                 if (dev->config) {
+01146                         u8              config = dev->config;
+01147 
+01148                         /* resets interface configuration, forgets about
+01149                          * previous transaction state (queued bufs, etc)
+01150                          * and re-inits endpoint state (toggle etc)
+01151                          * no response queued, just zero status == success.
+01152                          * if we had more than one interface we couldn't
+01153                          * use this "reset the config" shortcut.
+01154                          */
+01155                         zero_reset_config (dev);
+01156                         zero_set_config (dev, config, GFP_ATOMIC);
+01157                         value = 0;
+01158                 }
+01159                 spin_unlock (&dev->lock);
+01160                 break;
+01161         case USB_REQ_GET_INTERFACE:
+01162                 if ((ctrl->bRequestType == 0x21) && (ctrl->wIndex == 0x02)) {
+01163                         value = ctrl->wLength;
+01164                         break;
+01165                 }
+01166                 else {
+01167                         if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
+01168                                 goto unknown;
+01169                         if (!dev->config)
+01170                                 break;
+01171                         if (ctrl->wIndex != 0) {
+01172                                 value = -EDOM;
+01173                                 break;
+01174                         }
+01175                         *(u8 *)req->buf = 0;
+01176                         value = min (ctrl->wLength, (u16) 1);
+01177                 }
+01178                 break;
+01179 
+01180         /*
+01181          * These are the same vendor-specific requests supported by
+01182          * Intel's USB 2.0 compliance test devices.  We exceed that
+01183          * device spec by allowing multiple-packet requests.
+01184          */
+01185         case 0x5b:      /* control WRITE test -- fill the buffer */
+01186                 if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
+01187                         goto unknown;
+01188                 if (ctrl->wValue || ctrl->wIndex)
+01189                         break;
+01190                 /* just read that many bytes into the buffer */
+01191                 if (ctrl->wLength > USB_BUFSIZ)
+01192                         break;
+01193                 value = ctrl->wLength;
+01194                 break;
+01195         case 0x5c:      /* control READ test -- return the buffer */
+01196                 if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
+01197                         goto unknown;
+01198                 if (ctrl->wValue || ctrl->wIndex)
+01199                         break;
+01200                 /* expect those bytes are still in the buffer; send back */
+01201                 if (ctrl->wLength > USB_BUFSIZ
+01202                                 || ctrl->wLength != req->length)
+01203                         break;
+01204                 value = ctrl->wLength;
+01205                 break;
+01206 
+01207         case 0x01: // SET_CUR
+01208         case 0x02:
+01209         case 0x03:
+01210         case 0x04:
+01211         case 0x05:
+01212                 value = ctrl->wLength;
+01213                 break;
+01214         case 0x81:
+01215                 switch (ctrl->wValue) {
+01216                 case 0x0201:
+01217                 case 0x0202:
+01218                         ((u8*)req->buf)[0] = 0x00;
+01219                         ((u8*)req->buf)[1] = 0xe3;
+01220                         break;
+01221                 case 0x0300:
+01222                 case 0x0500:
+01223                         ((u8*)req->buf)[0] = 0x00;
+01224                         break;
+01225                 }
+01226                 //((u8*)req->buf)[0] = 0x81;
+01227                 //((u8*)req->buf)[1] = 0x81;
+01228                 value = ctrl->wLength;
+01229                 break;
+01230         case 0x82:
+01231                 switch (ctrl->wValue) {
+01232                 case 0x0201:
+01233                 case 0x0202:
+01234                         ((u8*)req->buf)[0] = 0x00;
+01235                         ((u8*)req->buf)[1] = 0xc3;
+01236                         break;
+01237                 case 0x0300:
+01238                 case 0x0500:
+01239                         ((u8*)req->buf)[0] = 0x00;
+01240                         break;
+01241                 }
+01242                 //((u8*)req->buf)[0] = 0x82;
+01243                 //((u8*)req->buf)[1] = 0x82;
+01244                 value = ctrl->wLength;
+01245                 break;
+01246         case 0x83:
+01247                 switch (ctrl->wValue) {
+01248                 case 0x0201:
+01249                 case 0x0202:
+01250                         ((u8*)req->buf)[0] = 0x00;
+01251                         ((u8*)req->buf)[1] = 0x00;
+01252                         break;
+01253                 case 0x0300:
+01254                         ((u8*)req->buf)[0] = 0x60;
+01255                         break;
+01256                 case 0x0500:    
+01257                         ((u8*)req->buf)[0] = 0x18;
+01258                         break;
+01259                 }
+01260                 //((u8*)req->buf)[0] = 0x83;
+01261                 //((u8*)req->buf)[1] = 0x83;
+01262                 value = ctrl->wLength;
+01263                 break;
+01264         case 0x84:
+01265                 switch (ctrl->wValue) {
+01266                 case 0x0201:
+01267                 case 0x0202:
+01268                         ((u8*)req->buf)[0] = 0x00;
+01269                         ((u8*)req->buf)[1] = 0x01;
+01270                         break;
+01271                 case 0x0300:
+01272                 case 0x0500:
+01273                         ((u8*)req->buf)[0] = 0x08;
+01274                         break;
+01275                 }
+01276                 //((u8*)req->buf)[0] = 0x84;
+01277                 //((u8*)req->buf)[1] = 0x84;
+01278                 value = ctrl->wLength;
+01279                 break;
+01280         case 0x85:
+01281                 ((u8*)req->buf)[0] = 0x85;
+01282                 ((u8*)req->buf)[1] = 0x85;
+01283                 value = ctrl->wLength;
+01284                 break;
+01285 
+01286         
+01287         default:
+01288 unknown:
+01289                 printk("unknown control req%02x.%02x v%04x i%04x l%d\n",
+01290                         ctrl->bRequestType, ctrl->bRequest,
+01291                         ctrl->wValue, ctrl->wIndex, ctrl->wLength);
+01292         }
+01293 
+01294         /* respond with data transfer before status phase? */
+01295         if (value >= 0) {
+01296                 req->length = value;
+01297                 req->zero = value < ctrl->wLength
+01298                                 && (value % gadget->ep0->maxpacket) == 0;
+01299                 value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
+01300                 if (value < 0) {
+01301                         DBG (dev, "ep_queue < 0 --> %d\n", value);
+01302                         req->status = 0;
+01303                         zero_setup_complete (gadget->ep0, req);
+01304                 }
+01305         }
+01306 
+01307         /* device either stalls (value < 0) or reports success */
+01308         return value;
+01309 }
+01310 
+01311 static void
+01312 zero_disconnect (struct usb_gadget *gadget)
+01313 {
+01314         struct zero_dev         *dev = get_gadget_data (gadget);
+01315         unsigned long           flags;
+01316 
+01317         spin_lock_irqsave (&dev->lock, flags);
+01318         zero_reset_config (dev);
+01319 
+01320         /* a more significant application might have some non-usb
+01321          * activities to quiesce here, saving resources like power
+01322          * or pushing the notification up a network stack.
+01323          */
+01324         spin_unlock_irqrestore (&dev->lock, flags);
+01325 
+01326         /* next we may get setup() calls to enumerate new connections;
+01327          * or an unbind() during shutdown (including removing module).
+01328          */
+01329 }
+01330 
+01331 static void
+01332 zero_autoresume (unsigned long _dev)
+01333 {
+01334         struct zero_dev *dev = (struct zero_dev *) _dev;
+01335         int             status;
+01336 
+01337         /* normally the host would be woken up for something
+01338          * more significant than just a timer firing...
+01339          */
+01340         if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
+01341                 status = usb_gadget_wakeup (dev->gadget);
+01342                 DBG (dev, "wakeup --> %d\n", status);
+01343         }
+01344 }
+01345 
+01346 /*-------------------------------------------------------------------------*/
+01347 
+01348 static void
+01349 zero_unbind (struct usb_gadget *gadget)
+01350 {
+01351         struct zero_dev         *dev = get_gadget_data (gadget);
+01352 
+01353         DBG (dev, "unbind\n");
+01354 
+01355         /* we've already been disconnected ... no i/o is active */
+01356         if (dev->req)
+01357                 free_ep_req (gadget->ep0, dev->req);
+01358         del_timer_sync (&dev->resume);
+01359         kfree (dev);
+01360         set_gadget_data (gadget, NULL);
+01361 }
+01362 
+01363 static int
+01364 zero_bind (struct usb_gadget *gadget)
+01365 {
+01366         struct zero_dev         *dev;
+01367         //struct usb_ep         *ep;
+01368 
+01369         printk("binding\n");
+01370         /*
+01371          * DRIVER POLICY CHOICE:  you may want to do this differently.
+01372          * One thing to avoid is reusing a bcdDevice revision code
+01373          * with different host-visible configurations or behavior
+01374          * restrictions -- using ep1in/ep2out vs ep1out/ep3in, etc
+01375          */
+01376         //device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201);
+01377 
+01378 
+01379         /* ok, we made sense of the hardware ... */
+01380         dev = kmalloc (sizeof *dev, SLAB_KERNEL);
+01381         if (!dev)
+01382                 return -ENOMEM;
+01383         memset (dev, 0, sizeof *dev);
+01384         spin_lock_init (&dev->lock);
+01385         dev->gadget = gadget;
+01386         set_gadget_data (gadget, dev);
+01387 
+01388         /* preallocate control response and buffer */
+01389         dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
+01390         if (!dev->req)
+01391                 goto enomem;
+01392         dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
+01393                                 &dev->req->dma, GFP_KERNEL);
+01394         if (!dev->req->buf)
+01395                 goto enomem;
+01396 
+01397         dev->req->complete = zero_setup_complete;
+01398 
+01399         device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
+01400 
+01401 #ifdef CONFIG_USB_GADGET_DUALSPEED
+01402         /* assume ep0 uses the same value for both speeds ... */
+01403         dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+01404 
+01405         /* and that all endpoints are dual-speed */
+01406         //hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
+01407         //hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
+01408 #endif
+01409 
+01410         usb_gadget_set_selfpowered (gadget);
+01411 
+01412         init_timer (&dev->resume);
+01413         dev->resume.function = zero_autoresume;
+01414         dev->resume.data = (unsigned long) dev;
+01415 
+01416         gadget->ep0->driver_data = dev;
+01417 
+01418         INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
+01419         INFO (dev, "using %s, OUT %s IN %s\n", gadget->name,
+01420                 EP_OUT_NAME, EP_IN_NAME);
+01421 
+01422         snprintf (manufacturer, sizeof manufacturer,
+01423                 UTS_SYSNAME " " UTS_RELEASE " with %s",
+01424                 gadget->name);
+01425 
+01426         return 0;
+01427 
+01428 enomem:
+01429         zero_unbind (gadget);
+01430         return -ENOMEM;
+01431 }
+01432 
+01433 /*-------------------------------------------------------------------------*/
+01434 
+01435 static void
+01436 zero_suspend (struct usb_gadget *gadget)
+01437 {
+01438         struct zero_dev         *dev = get_gadget_data (gadget);
+01439 
+01440         if (gadget->speed == USB_SPEED_UNKNOWN)
+01441                 return;
+01442 
+01443         if (autoresume) {
+01444                 mod_timer (&dev->resume, jiffies + (HZ * autoresume));
+01445                 DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);
+01446         } else
+01447                 DBG (dev, "suspend\n");
+01448 }
+01449 
+01450 static void
+01451 zero_resume (struct usb_gadget *gadget)
+01452 {
+01453         struct zero_dev         *dev = get_gadget_data (gadget);
+01454 
+01455         DBG (dev, "resume\n");
+01456         del_timer (&dev->resume);
+01457 }
+01458 
+01459 
+01460 /*-------------------------------------------------------------------------*/
+01461 
+01462 static struct usb_gadget_driver zero_driver = {
+01463 #ifdef CONFIG_USB_GADGET_DUALSPEED
+01464         .speed          = USB_SPEED_HIGH,
+01465 #else
+01466         .speed          = USB_SPEED_FULL,
+01467 #endif
+01468         .function       = (char *) longname,
+01469         .bind           = zero_bind,
+01470         .unbind         = zero_unbind,
+01471 
+01472         .setup          = zero_setup,
+01473         .disconnect     = zero_disconnect,
+01474 
+01475         .suspend        = zero_suspend,
+01476         .resume         = zero_resume,
+01477 
+01478         .driver         = {
+01479                 .name           = (char *) shortname,
+01480                 // .shutdown = ...
+01481                 // .suspend = ...
+01482                 // .resume = ...
+01483         },
+01484 };
+01485 
+01486 MODULE_AUTHOR ("David Brownell");
+01487 MODULE_LICENSE ("Dual BSD/GPL");
+01488 
+01489 static struct proc_dir_entry *pdir, *pfile;
+01490 
+01491 static int isoc_read_data (char *page, char **start,
+01492                            off_t off, int count,
+01493                            int *eof, void *data)
+01494 {
+01495         int i;
+01496         static int c = 0;
+01497         static int done = 0;
+01498         static int s = 0;
+01499 
+01500 /*
+01501         printk ("\ncount: %d\n", count);
+01502         printk ("rbuf_start: %d\n", rbuf_start);
+01503         printk ("rbuf_len: %d\n", rbuf_len);
+01504         printk ("off: %d\n", off);
+01505         printk ("start: %p\n\n", *start);
+01506 */
+01507         if (done) {
+01508                 c = 0;
+01509                 done = 0;
+01510                 *eof = 1;
+01511                 return 0;
+01512         }
+01513 
+01514         if (c == 0) {
+01515                 if (rbuf_len == RBUF_LEN)
+01516                         s = rbuf_start;
+01517                 else s = 0;
+01518         }
+01519 
+01520         for (i=0; i<count && c<rbuf_len; i++, c++) {
+01521                 page[i] = rbuf[(c+s) % RBUF_LEN];
+01522         }
+01523         *start = page;
+01524         
+01525         if (c >= rbuf_len) {
+01526                 *eof = 1;
+01527                 done = 1;
+01528         }
+01529 
+01530 
+01531         return i;
+01532 }
+01533 
+01534 static int __init init (void)
+01535 {
+01536 
+01537         int retval = 0;
+01538 
+01539         pdir = proc_mkdir("isoc_test", NULL);
+01540         if(pdir == NULL) {
+01541                 retval = -ENOMEM;
+01542                 printk("Error creating dir\n");
+01543                 goto done;
+01544         }
+01545         pdir->owner = THIS_MODULE;
+01546 
+01547         pfile = create_proc_read_entry("isoc_data",
+01548                                        0444, pdir,
+01549                                        isoc_read_data,
+01550                                        NULL);
+01551         if (pfile == NULL) {
+01552                 retval = -ENOMEM;
+01553                 printk("Error creating file\n");
+01554                 goto no_file;
+01555         }
+01556         pfile->owner = THIS_MODULE;
+01557 
+01558         return usb_gadget_register_driver (&zero_driver);
+01559 
+01560  no_file:
+01561         remove_proc_entry("isoc_data", NULL);
+01562  done:
+01563         return retval;
+01564 }
+01565 module_init (init);
+01566 
+01567 static void __exit cleanup (void)
+01568 {
+01569 
+01570         usb_gadget_unregister_driver (&zero_driver);
+01571         
+01572         remove_proc_entry("isoc_data", pdir);
+01573         remove_proc_entry("isoc_test", NULL);
+01574 }
+01575 module_exit (cleanup);
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__cfi__common_8h-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__cfi__common_8h-source.html new file mode 100644 index 000000000000..d055a8e41284 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__cfi__common_8h-source.html @@ -0,0 +1,115 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_cfi_common.h Source File + + + + + + +

dwc_cfi_common.h

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00003  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00004  * otherwise expressly agreed to in writing between Synopsys and you.
+00005  * 
+00006  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00007  * any End User Software License Agreement or Agreement for Licensed Product
+00008  * with Synopsys or any supplement thereto. You are permitted to use and
+00009  * redistribute this Software in source and binary forms, with or without
+00010  * modification, provided that redistributions of source code must retain this
+00011  * notice. You may not view, use, disclose, copy or distribute this file or
+00012  * any information contained herein except pursuant to this license grant from
+00013  * Synopsys. If you do not agree with this notice, including the disclaimer
+00014  * below, then you are not authorized to use the Software.
+00015  * 
+00016  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00017  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00018  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00019  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00020  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00021  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00022  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00023  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00024  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00025  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00026  * DAMAGE.
+00027  * ========================================================================== */
+00028 
+00029 #if !defined(__DWC_CFI_COMMON_H__)
+00030 #define __DWC_CFI_COMMON_H__
+00031 
+00032 //#include <linux/types.h>
+00033 
+00044 #define VEN_CORE_GET_FEATURES           0xB1
+00045 
+00047 #define VEN_CORE_GET_FEATURE            0xB2
+00048 
+00050 #define VEN_CORE_SET_FEATURE            0xB3
+00051 
+00055 #define VEN_CORE_RESET_FEATURES         0xB4
+00056 
+00058 #define VEN_CORE_ACTIVATE_FEATURES      0xB5
+00059 
+00061 #define VEN_CORE_READ_REGISTER          0xB6
+00062 
+00064 #define VEN_CORE_WRITE_REGISTER         0xB7
+00065 
+00069 struct cfi_all_features_header {
+00071 #define CFI_ALL_FEATURES_HDR_LEN                8
+00072 
+00075         uint16_t wTotalLen;
+00076 
+00082         uint16_t wVersion;
+00083 
+00085         uint16_t wCoreID;
+00086 #define CFI_CORE_ID_UDC         1
+00087 #define CFI_CORE_ID_OTG         2
+00088 #define CFI_CORE_ID_WUDEV       3
+00089 
+00091         uint16_t wNumFeatures;
+00092 } UPACKED;
+00093 
+00094 typedef struct cfi_all_features_header cfi_all_features_header_t;
+00095 
+00099 struct cfi_feature_desc_header {
+00100 #define CFI_FEATURE_DESC_HDR_LEN        8
+00101 
+00103         uint16_t wFeatureID;
+00104 
+00108         uint16_t wLength;
+00109 
+00111         uint16_t wDataLength;
+00112 
+00119         uint8_t bmAttributes;
+00120 #define CFI_FEATURE_ATTR_RO             1
+00121 #define CFI_FEATURE_ATTR_RW             0
+00122 
+00124         uint8_t bNameLen;
+00125 
+00127         //uint8_t *name;
+00128 } UPACKED;
+00129 
+00130 typedef struct cfi_feature_desc_header cfi_feature_desc_header_t;
+00131 
+00136 struct cfi_string {
+00137         uint16_t id;
+00138         const uint8_t *s;
+00139 };
+00140 typedef struct cfi_string cfi_string_t;
+00141 
+00142 #endif
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__cfi__common_8h.html b/drivers/usb/host/dwc_otg/doc/html/dwc__cfi__common_8h.html new file mode 100644 index 000000000000..d1e12d0d0dd8 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__cfi__common_8h.html @@ -0,0 +1,119 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_cfi_common.h File Reference + + + + + + +

dwc_cfi_common.h File Reference

This file contains the CFI specific common constants, interfaces (functions and macros) and structures for Linux. More... +

+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Structures

struct  cfi_all_features_header
 This structure is the header of the Core Features dataset returned to the Host. More...
struct  cfi_feature_desc_header
 This structure is a header of the Core Feature descriptor dataset returned to the Host after the VEN_CORE_GET_FEATURES request. More...
struct  cfi_string
 This structure describes a NULL terminated string referenced by its id field. More...

Defines

+#define __DWC_CFI_COMMON_H__
+#define VEN_CORE_GET_FEATURES   0xB1
 This is a request for all Core Features.
+#define VEN_CORE_GET_FEATURE   0xB2
 This is a request to get the value of a specific Core Feature.
+#define VEN_CORE_SET_FEATURE   0xB3
 This command allows the host to set the value of a specific Core Feature.
+#define VEN_CORE_RESET_FEATURES   0xB4
 This command allows the host to set the default values of either all or any specific Core Feature.
+#define VEN_CORE_ACTIVATE_FEATURES   0xB5
 This command forces the PCD to write the deferred values of a Core Features.
+#define VEN_CORE_READ_REGISTER   0xB6
 This request reads a DWORD value from a register at the specified offset.
+#define VEN_CORE_WRITE_REGISTER   0xB7
 This request writes a DWORD value into a register at the specified offset.
+#define CFI_ALL_FEATURES_HDR_LEN   8
 The features header structure length is.
+#define CFI_CORE_ID_UDC   1
+#define CFI_CORE_ID_OTG   2
+#define CFI_CORE_ID_WUDEV   3
+#define CFI_FEATURE_DESC_HDR_LEN   8
+#define CFI_FEATURE_ATTR_RO   1
+#define CFI_FEATURE_ATTR_RW   0

Typedefs

+typedef cfi_all_features_header cfi_all_features_header_t
+typedef cfi_feature_desc_header cfi_feature_desc_header_t
+typedef cfi_string cfi_string_t

Variables

+cfi_all_features_header UPACKED
 This structure is the header of the Core Features dataset returned to the Host.
+cfi_feature_desc_header UPACKED
 This structure is a header of the Core Feature descriptor dataset returned to the Host after the VEN_CORE_GET_FEATURES request.
+


Detailed Description

+This file contains the CFI specific common constants, interfaces (functions and macros) and structures for Linux. +

+No PCD specific data structure or definition is to be included in this file. +

+Definition in file dwc_cfi_common.h.


Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__attr_8c-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__attr_8c-source.html new file mode 100644 index 000000000000..2602e5509a90 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__attr_8c-source.html @@ -0,0 +1,828 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_attr.c Source File + + + + + + +

dwc_otg_attr.c

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.c $
+00003  * $Revision: #35 $
+00004  * $Date: 2009/04/03 $
+00005  * $Change: 1225160 $
+00006  *
+00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009  * otherwise expressly agreed to in writing between Synopsys and you.
+00010  *
+00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012  * any End User Software License Agreement or Agreement for Licensed Product
+00013  * with Synopsys or any supplement thereto. You are permitted to use and
+00014  * redistribute this Software in source and binary forms, with or without
+00015  * modification, provided that redistributions of source code must retain this
+00016  * notice. You may not view, use, disclose, copy or distribute this file or
+00017  * any information contained herein except pursuant to this license grant from
+00018  * Synopsys. If you do not agree with this notice, including the disclaimer
+00019  * below, then you are not authorized to use the Software.
+00020  *
+00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031  * DAMAGE.
+00032  * ========================================================================== */
+00033 
+00286 #include <linux/kernel.h>
+00287 #include <linux/module.h>
+00288 #include <linux/moduleparam.h>
+00289 #include <linux/init.h>
+00290 #include <linux/device.h>
+00291 #include <linux/errno.h>
+00292 #include <linux/types.h>
+00293 #include <linux/stat.h>         /* permission constants */
+00294 #include <linux/version.h>
+00295 #include <linux/param.h>
+00296 #include <linux/delay.h>
+00297 #include <linux/jiffies.h>
+00298 
+00299 
+00300 #ifdef LM_INTERFACE
+00301 #include <asm/sizes.h>
+00302 #include <asm/arch/lm.h>
+00303 #endif
+00304 
+00305 #include <asm/io.h>
+00306 
+00307 #include "dwc_os.h"
+00308 #include "dwc_otg_driver.h"
+00309 #include "dwc_otg_attr.h"
+00310 #include "dwc_otg_core_if.h"
+00311 #include "dwc_otg_pcd_if.h"
+00312 #include "dwc_otg_hcd_if.h"
+00313 
+00314 /*
+00315  * MACROs for defining sysfs attribute
+00316  */
+00317 #ifdef LM_INTERFACE
+00318 
+00319 #define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
+00320 static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
+00321 { \
+00322         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
+00323         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);             \
+00324         uint32_t val; \
+00325         val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
+00326         return sprintf (buf, "%s = 0x%x\n", _string_, val); \
+00327 }
+00328 #define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
+00329 static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
+00330                                         const char *buf, size_t count) \
+00331 { \
+00332         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
+00333         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
+00334         uint32_t set = simple_strtoul(buf, NULL, 16); \
+00335         dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
+00336         return count; \
+00337 }
+00338 
+00339 #elif PCI_INTERFACE
+00340 
+00341 #define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
+00342 static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
+00343 { \
+00344         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);      \
+00345         uint32_t val; \
+00346         val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
+00347         return sprintf (buf, "%s = 0x%x\n", _string_, val); \
+00348 }
+00349 #define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
+00350 static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
+00351                                         const char *buf, size_t count) \
+00352 { \
+00353         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);  \
+00354         uint32_t set = simple_strtoul(buf, NULL, 16); \
+00355         dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\
+00356         return count; \
+00357 }
+00358 
+00359 #endif
+00360 
+00361 /*
+00362  * MACROs for defining sysfs attribute for 32-bit registers
+00363  */
+00364 #ifdef LM_INTERFACE
+00365 #define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
+00366 static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
+00367 { \
+00368         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
+00369         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
+00370         uint32_t val; \
+00371         val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
+00372         return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
+00373 }
+00374 #define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
+00375 static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
+00376                                         const char *buf, size_t count) \
+00377 { \
+00378         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \
+00379         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \
+00380         uint32_t val = simple_strtoul(buf, NULL, 16); \
+00381         dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
+00382         return count; \
+00383 }
+00384 #elif PCI_INTERFACE
+00385 #define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
+00386 static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \
+00387 { \
+00388         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);  \
+00389         uint32_t val; \
+00390         val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \
+00391         return sprintf (buf, "%s = 0x%08x\n", _string_, val); \
+00392 }
+00393 #define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
+00394 static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \
+00395                                         const char *buf, size_t count) \
+00396 { \
+00397         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);  \
+00398         uint32_t val = simple_strtoul(buf, NULL, 16); \
+00399         dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \
+00400         return count; \
+00401 }
+00402 
+00403 #endif
+00404 
+00405 #define DWC_OTG_DEVICE_ATTR_BITFIELD_RW(_otg_attr_name_,_string_) \
+00406 DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
+00407 DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
+00408 DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
+00409 
+00410 #define DWC_OTG_DEVICE_ATTR_BITFIELD_RO(_otg_attr_name_,_string_) \
+00411 DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
+00412 DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
+00413 
+00414 #define DWC_OTG_DEVICE_ATTR_REG32_RW(_otg_attr_name_,_addr_,_string_) \
+00415 DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
+00416 DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
+00417 DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
+00418 
+00419 #define DWC_OTG_DEVICE_ATTR_REG32_RO(_otg_attr_name_,_addr_,_string_) \
+00420 DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
+00421 DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
+00422 
+00429 static ssize_t regoffset_show(struct device *_dev,
+00430                               struct device_attribute *attr, char *buf)
+00431 {
+00432 #ifdef LM_INTERFACE
+00433         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00434         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00435 #elif PCI_INTERFACE
+00436         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00437 #endif
+00438 
+00439         return snprintf(buf, sizeof("0xFFFFFFFF\n") + 1, "0x%08x\n",
+00440                         otg_dev->reg_offset);
+00441 }
+00442 
+00446 static ssize_t regoffset_store(struct device *_dev,
+00447                                struct device_attribute *attr,
+00448                                const char *buf, size_t count)
+00449 {
+00450 #ifdef LM_INTERFACE
+00451         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00452         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00453 #elif PCI_INTERFACE
+00454         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00455 #endif
+00456 
+00457         uint32_t offset = simple_strtoul(buf, NULL, 16);
+00458 #ifdef LM_INTERFACE
+00459         if (offset < SZ_256K) {
+00460 #elif  PCI_INTERFACE
+00461         if (offset < 0x00040000) {
+00462 #endif
+00463                 otg_dev->reg_offset = offset;
+00464         } else {
+00465                 dev_err(_dev, "invalid offset\n");
+00466         }
+00467 
+00468         return count;
+00469 }
+00470 
+00471 DEVICE_ATTR(regoffset, S_IRUGO | S_IWUSR, regoffset_show, regoffset_store);
+00472 
+00477 static ssize_t regvalue_show(struct device *_dev,
+00478                              struct device_attribute *attr, char *buf)
+00479 {
+00480 #ifdef LM_INTERFACE
+00481         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00482         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00483 #elif PCI_INTERFACE
+00484         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00485 #endif
+00486 
+00487         uint32_t val;
+00488         volatile uint32_t *addr;
+00489 
+00490         if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) {
+00491                 /* Calculate the address */
+00492                 addr = (uint32_t *) (otg_dev->reg_offset +
+00493                                      (uint8_t *) otg_dev->base);
+00494                 val = dwc_read_reg32(addr);
+00495                 return snprintf(buf,
+00496                                 sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n") + 1,
+00497                                 "Reg@0x%06x = 0x%08x\n", otg_dev->reg_offset,
+00498                                 val);
+00499         } else {
+00500                 dev_err(_dev, "Invalid offset (0x%0x)\n", otg_dev->reg_offset);
+00501                 return sprintf(buf, "invalid offset\n");
+00502         }
+00503 }
+00504 
+00510 static ssize_t regvalue_store(struct device *_dev,
+00511                               struct device_attribute *attr,
+00512                               const char *buf, size_t count)
+00513 {
+00514 #ifdef LM_INTERFACE
+00515         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00516         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00517 #elif PCI_INTERFACE
+00518         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00519 #endif
+00520 
+00521         volatile uint32_t *addr;
+00522         uint32_t val = simple_strtoul(buf, NULL, 16);
+00523         //dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val);
+00524         if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) {
+00525                 /* Calculate the address */
+00526                 addr = (uint32_t *) (otg_dev->reg_offset +
+00527                                      (uint8_t *) otg_dev->base);
+00528                 dwc_write_reg32(addr, val);
+00529         } else {
+00530                 dev_err(_dev, "Invalid Register Offset (0x%08x)\n",
+00531                         otg_dev->reg_offset);
+00532         }
+00533         return count;
+00534 }
+00535 
+00536 DEVICE_ATTR(regvalue, S_IRUGO | S_IWUSR, regvalue_show, regvalue_store);
+00537 
+00538 /*
+00539  * Attributes
+00540  */
+00541 DWC_OTG_DEVICE_ATTR_BITFIELD_RO(mode, "Mode");
+00542 DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hnpcapable, "HNPCapable");
+00543 DWC_OTG_DEVICE_ATTR_BITFIELD_RW(srpcapable, "Mode");
+00544 DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hsic_connect, "HSIC Connect");
+00545 DWC_OTG_DEVICE_ATTR_BITFIELD_RW(inv_sel_hsic, "Invert Select HSIC");
+00546 
+00547 //DWC_OTG_DEVICE_ATTR_BITFIELD_RW(buspower,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
+00548 //DWC_OTG_DEVICE_ATTR_BITFIELD_RW(bussuspend,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode");
+00549 DWC_OTG_DEVICE_ATTR_BITFIELD_RO(busconnected, "Bus Connected");
+00550 
+00551 DWC_OTG_DEVICE_ATTR_REG32_RW(gotgctl, 0, "GOTGCTL");
+00552 DWC_OTG_DEVICE_ATTR_REG32_RW(gusbcfg,
+00553                              &(otg_dev->core_if->core_global_regs->gusbcfg),
+00554                              "GUSBCFG");
+00555 DWC_OTG_DEVICE_ATTR_REG32_RW(grxfsiz,
+00556                              &(otg_dev->core_if->core_global_regs->grxfsiz),
+00557                              "GRXFSIZ");
+00558 DWC_OTG_DEVICE_ATTR_REG32_RW(gnptxfsiz,
+00559                              &(otg_dev->core_if->core_global_regs->gnptxfsiz),
+00560                              "GNPTXFSIZ");
+00561 DWC_OTG_DEVICE_ATTR_REG32_RW(gpvndctl,
+00562                              &(otg_dev->core_if->core_global_regs->gpvndctl),
+00563                              "GPVNDCTL");
+00564 DWC_OTG_DEVICE_ATTR_REG32_RW(ggpio,
+00565                              &(otg_dev->core_if->core_global_regs->ggpio),
+00566                              "GGPIO");
+00567 DWC_OTG_DEVICE_ATTR_REG32_RW(guid, &(otg_dev->core_if->core_global_regs->guid),
+00568                              "GUID");
+00569 DWC_OTG_DEVICE_ATTR_REG32_RO(gsnpsid,
+00570                              &(otg_dev->core_if->core_global_regs->gsnpsid),
+00571                              "GSNPSID");
+00572 DWC_OTG_DEVICE_ATTR_BITFIELD_RW(devspeed, "Device Speed");
+00573 DWC_OTG_DEVICE_ATTR_BITFIELD_RO(enumspeed, "Device Enumeration Speed");
+00574 
+00575 DWC_OTG_DEVICE_ATTR_REG32_RO(hptxfsiz,
+00576                              &(otg_dev->core_if->core_global_regs->hptxfsiz),
+00577                              "HPTXFSIZ");
+00578 DWC_OTG_DEVICE_ATTR_REG32_RW(hprt0, otg_dev->core_if->host_if->hprt0, "HPRT0");
+00579 
+00586 static ssize_t hnp_show(struct device *_dev,
+00587                         struct device_attribute *attr, char *buf)
+00588 {
+00589 #ifdef LM_INTERFACE
+00590         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00591         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00592 #elif PCI_INTERFACE
+00593         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00594 #endif
+00595         return sprintf(buf, "HstNegScs = 0x%x\n",
+00596                        dwc_otg_get_hnpstatus(otg_dev->core_if));
+00597 }
+00598 
+00602 static ssize_t hnp_store(struct device *_dev,
+00603                          struct device_attribute *attr,
+00604                          const char *buf, size_t count)
+00605 {
+00606 #ifdef LM_INTERFACE
+00607         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00608         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00609 #elif PCI_INTERFACE
+00610         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00611 #endif
+00612         uint32_t in = simple_strtoul(buf, NULL, 16);
+00613         dwc_otg_set_hnpreq(otg_dev->core_if, in);
+00614         return count;
+00615 }
+00616 
+00617 DEVICE_ATTR(hnp, 0644, hnp_show, hnp_store);
+00618 
+00625 static ssize_t srp_show(struct device *_dev,
+00626                         struct device_attribute *attr, char *buf)
+00627 {
+00628 #ifndef DWC_HOST_ONLY
+00629 #ifdef LM_INTERFACE
+00630         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00631         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00632 #elif PCI_INTERFACE
+00633         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00634 #endif
+00635         return sprintf(buf, "SesReqScs = 0x%x\n",
+00636                        dwc_otg_get_srpstatus(otg_dev->core_if));
+00637 #else
+00638         return sprintf(buf, "Host Only Mode!\n");
+00639 #endif
+00640 }
+00641 
+00645 static ssize_t srp_store(struct device *_dev,
+00646                          struct device_attribute *attr,
+00647                          const char *buf, size_t count)
+00648 {
+00649 #ifndef DWC_HOST_ONLY
+00650 #ifdef LM_INTERFACE
+00651         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00652         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00653 #elif PCI_INTERFACE
+00654         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00655 #endif
+00656         dwc_otg_pcd_initiate_srp(otg_dev->pcd);
+00657 #endif
+00658         return count;
+00659 }
+00660 
+00661 DEVICE_ATTR(srp, 0644, srp_show, srp_store);
+00662 
+00669 static ssize_t buspower_show(struct device *_dev,
+00670                              struct device_attribute *attr, char *buf)
+00671 {
+00672 #ifdef LM_INTERFACE
+00673         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00674         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00675 #elif PCI_INTERFACE
+00676         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00677 #endif
+00678         return sprintf(buf, "Bus Power = 0x%x\n",
+00679                        dwc_otg_get_prtpower(otg_dev->core_if));
+00680 }
+00681 
+00685 static ssize_t buspower_store(struct device *_dev,
+00686                               struct device_attribute *attr,
+00687                               const char *buf, size_t count)
+00688 {
+00689 #ifdef LM_INTERFACE
+00690         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00691         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00692 #elif PCI_INTERFACE
+00693         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00694 #endif
+00695         uint32_t on = simple_strtoul(buf, NULL, 16);
+00696         dwc_otg_set_prtpower(otg_dev->core_if, on);
+00697         return count;
+00698 }
+00699 
+00700 DEVICE_ATTR(buspower, 0644, buspower_show, buspower_store);
+00701 
+00708 static ssize_t bussuspend_show(struct device *_dev,
+00709                                struct device_attribute *attr, char *buf)
+00710 {
+00711 #ifdef LM_INTERFACE
+00712         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00713         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00714 #elif PCI_INTERFACE
+00715         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00716 #endif
+00717 
+00718         return sprintf(buf, "Bus Suspend = 0x%x\n",
+00719                        dwc_otg_get_prtsuspend(otg_dev->core_if));
+00720 }
+00721 
+00725 static ssize_t bussuspend_store(struct device *_dev,
+00726                                 struct device_attribute *attr,
+00727                                 const char *buf, size_t count)
+00728 {
+00729 #ifdef LM_INTERFACE
+00730         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00731         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00732 #elif PCI_INTERFACE
+00733         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00734 #endif
+00735 
+00736         uint32_t in = simple_strtoul(buf, NULL, 16);
+00737         dwc_otg_set_prtsuspend(otg_dev->core_if, in);
+00738         return count;
+00739 }
+00740 
+00741 DEVICE_ATTR(bussuspend, 0644, bussuspend_show, bussuspend_store);
+00742 
+00746 static ssize_t remote_wakeup_show(struct device *_dev,
+00747                                   struct device_attribute *attr, char *buf)
+00748 {
+00749 #ifndef DWC_HOST_ONLY
+00750 #ifdef LM_INTERFACE
+00751         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00752         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00753 #elif PCI_INTERFACE
+00754         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00755 #endif
+00756 
+00757         return sprintf(buf,
+00758                        "Remote Wakeup Sig = %d Enabled = %d LPM Remote Wakeup = %d\n",
+00759                        dwc_otg_get_remotewakesig(otg_dev->core_if),
+00760                        dwc_otg_pcd_get_rmwkup_enable(otg_dev->pcd),
+00761                        dwc_otg_get_lpm_remotewakeenabled(otg_dev->core_if));
+00762 #else
+00763         return sprintf(buf, "Host Only Mode!\n");
+00764 #endif /* DWC_HOST_ONLY */
+00765 }
+00766 
+00773 static ssize_t remote_wakeup_store(struct device *_dev,
+00774                                    struct device_attribute *attr,
+00775                                    const char *buf, size_t count)
+00776 {
+00777 #ifndef DWC_HOST_ONLY
+00778 #ifdef LM_INTERFACE
+00779         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00780         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00781 #elif PCI_INTERFACE
+00782         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00783 #endif
+00784 
+00785         uint32_t val = simple_strtoul(buf, NULL, 16);
+00786 
+00787         if (val & 1) {
+00788                 dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 1);
+00789         } else {
+00790                 dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 0);
+00791         }
+00792 #endif /* DWC_HOST_ONLY */
+00793         return count;
+00794 }
+00795 
+00796 DEVICE_ATTR(remote_wakeup, S_IRUGO | S_IWUSR, remote_wakeup_show,
+00797             remote_wakeup_store);
+00798 
+00803 static ssize_t regdump_show(struct device *_dev,
+00804                             struct device_attribute *attr, char *buf)
+00805 {
+00806 #ifdef LM_INTERFACE
+00807         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00808         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00809 #elif PCI_INTERFACE
+00810         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00811 #endif
+00812 
+00813         dwc_otg_dump_global_registers(otg_dev->core_if);
+00814         if (dwc_otg_is_host_mode(otg_dev->core_if)) {
+00815                 dwc_otg_dump_host_registers(otg_dev->core_if);
+00816         } else {
+00817                 dwc_otg_dump_dev_registers(otg_dev->core_if);
+00818 
+00819         }
+00820         return sprintf(buf, "Register Dump\n");
+00821 }
+00822 
+00823 DEVICE_ATTR(regdump, S_IRUGO | S_IWUSR, regdump_show, 0);
+00824 
+00829 static ssize_t spramdump_show(struct device *_dev,
+00830                               struct device_attribute *attr, char *buf)
+00831 {
+00832 #ifdef LM_INTERFACE
+00833         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00834         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00835 #elif PCI_INTERFACE
+00836         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00837 #endif
+00838 
+00839         dwc_otg_dump_spram(otg_dev->core_if);
+00840 
+00841         return sprintf(buf, "SPRAM Dump\n");
+00842 }
+00843 
+00844 DEVICE_ATTR(spramdump, S_IRUGO | S_IWUSR, spramdump_show, 0);
+00845 
+00849 static ssize_t hcddump_show(struct device *_dev,
+00850                             struct device_attribute *attr, char *buf)
+00851 {
+00852 #ifndef DWC_DEVICE_ONLY
+00853 #ifdef LM_INTERFACE
+00854         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00855         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00856 #elif PCI_INTERFACE
+00857         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00858 #endif
+00859 
+00860         dwc_otg_hcd_dump_state(otg_dev->hcd);
+00861 #endif /* DWC_DEVICE_ONLY */
+00862         return sprintf(buf, "HCD Dump\n");
+00863 }
+00864 
+00865 DEVICE_ATTR(hcddump, S_IRUGO | S_IWUSR, hcddump_show, 0);
+00866 
+00872 static ssize_t hcd_frrem_show(struct device *_dev,
+00873                               struct device_attribute *attr, char *buf)
+00874 {
+00875 #ifndef DWC_DEVICE_ONLY
+00876 #ifdef LM_INTERFACE
+00877         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00878         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00879 #elif PCI_INTERFACE
+00880         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00881 #endif
+00882 
+00883         dwc_otg_hcd_dump_frrem(otg_dev->hcd);
+00884 #endif /* DWC_DEVICE_ONLY */
+00885         return sprintf(buf, "HCD Dump Frame Remaining\n");
+00886 }
+00887 
+00888 DEVICE_ATTR(hcd_frrem, S_IRUGO | S_IWUSR, hcd_frrem_show, 0);
+00889 
+00894 #define RW_REG_COUNT 10000000
+00895 #define MSEC_PER_JIFFIE 1000/HZ
+00896 static ssize_t rd_reg_test_show(struct device *_dev,
+00897                                 struct device_attribute *attr, char *buf)
+00898 {
+00899 #ifdef LM_INTERFACE
+00900         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00901         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00902 #elif PCI_INTERFACE
+00903         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00904 #endif
+00905 
+00906         int i;
+00907         int time;
+00908         int start_jiffies;
+00909 
+00910         printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
+00911                HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
+00912         start_jiffies = jiffies;
+00913         for (i = 0; i < RW_REG_COUNT; i++) {
+00914                 dwc_otg_get_gnptxfsiz(otg_dev->core_if);
+00915         }
+00916         time = jiffies - start_jiffies;
+00917         return sprintf(buf,
+00918                        "Time to read GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
+00919                        RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
+00920 }
+00921 
+00922 DEVICE_ATTR(rd_reg_test, S_IRUGO | S_IWUSR, rd_reg_test_show, 0);
+00923 
+00928 static ssize_t wr_reg_test_show(struct device *_dev,
+00929                                 struct device_attribute *attr, char *buf)
+00930 {
+00931 #ifdef LM_INTERFACE
+00932         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00933         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00934 #elif PCI_INTERFACE
+00935         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00936 #endif
+00937 
+00938         uint32_t reg_val;
+00939         int i;
+00940         int time;
+00941         int start_jiffies;
+00942 
+00943         printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
+00944                HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
+00945         reg_val = dwc_otg_get_gnptxfsiz(otg_dev->core_if);
+00946         start_jiffies = jiffies;
+00947         for (i = 0; i < RW_REG_COUNT; i++) {
+00948                 dwc_otg_set_gnptxfsiz(otg_dev->core_if, reg_val);
+00949         }
+00950         time = jiffies - start_jiffies;
+00951         return sprintf(buf,
+00952                        "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
+00953                        RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
+00954 }
+00955 
+00956 DEVICE_ATTR(wr_reg_test, S_IRUGO | S_IWUSR, wr_reg_test_show, 0);
+00957 
+00958 #ifdef CONFIG_USB_DWC_OTG_LPM
+00959 
+00963 static ssize_t lpmresp_show(struct device *_dev,
+00964                             struct device_attribute *attr, char *buf)
+00965 {
+00966 #ifdef LM_INTERFACE
+00967         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00968         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00969 #elif PCI_INTERFACE
+00970         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00971 #endif
+00972 
+00973         if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if))
+00974                 return sprintf(buf, "** LPM is DISABLED **\n");
+00975 
+00976         if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
+00977                 return sprintf(buf, "** Current mode is not device mode\n");
+00978         }
+00979         return sprintf(buf, "lpm_response = %d\n",
+00980                        dwc_otg_get_lpmresponse(otg_dev->core_if));
+00981 }
+00982 
+00986 static ssize_t lpmresp_store(struct device *_dev,
+00987                              struct device_attribute *attr,
+00988                              const char *buf, size_t count)
+00989 {
+00990 #ifdef LM_INTERFACE
+00991         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+00992         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+00993 #elif PCI_INTERFACE
+00994         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+00995 #endif
+00996 
+00997         uint32_t val = simple_strtoul(buf, NULL, 16);
+00998 
+00999         if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if)) {
+01000                 return 0;
+01001         }
+01002 
+01003         if (!dwc_otg_is_device_mode(otg_dev->core_if)) {
+01004                 return 0;
+01005         }
+01006 
+01007         dwc_otg_set_lpmresponse(otg_dev->core_if, val);
+01008         return count;
+01009 }
+01010 
+01011 DEVICE_ATTR(lpm_response, S_IRUGO | S_IWUSR, lpmresp_show, lpmresp_store);
+01012 
+01016 static ssize_t sleepstatus_show(struct device *_dev,
+01017                                 struct device_attribute *attr, char *buf)
+01018 {
+01019 #ifdef LM_INTERFACE
+01020         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+01021         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+01022 #elif PCI_INTERFACE
+01023         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+01024 #endif
+01025 
+01026 
+01027         return sprintf(buf, "Sleep Status = %d\n",
+01028                        dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if));
+01029 }
+01030 
+01034 static ssize_t sleepstatus_store(struct device *_dev,
+01035                                  struct device_attribute *attr,
+01036                                  const char *buf, size_t count)
+01037 {
+01038 #ifdef LM_INTERFACE
+01039         struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
+01040         dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
+01041 #elif PCI_INTERFACE
+01042         dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
+01043 #endif
+01044 
+01045         dwc_otg_core_if_t *core_if = otg_dev->core_if;
+01046 
+01047         if (dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if)) {
+01048                 if (dwc_otg_is_host_mode(core_if)) {
+01049 
+01050                         DWC_PRINTF("Host initiated resume\n");
+01051                         dwc_otg_set_prtresume(otg_dev->core_if, 1);
+01052                 }
+01053         }
+01054 
+01055         return count;
+01056 }
+01057 
+01058 DEVICE_ATTR(sleep_status, S_IRUGO | S_IWUSR, sleepstatus_show,
+01059             sleepstatus_store);
+01060 
+01061 #endif                          /* CONFIG_USB_DWC_OTG_LPM_ENABLE */
+01062 
+01068 void dwc_otg_attr_create (
+01069 #ifdef LM_INTERFACE
+01070         struct lm_device *dev
+01071 #elif  PCI_INTERFACE
+01072         struct pci_dev *dev
+01073 #endif
+01074         )
+01075 
+01076 {
+01077         int error;
+01078 
+01079         error = device_create_file(&dev->dev, &dev_attr_regoffset);
+01080         error = device_create_file(&dev->dev, &dev_attr_regvalue);
+01081         error = device_create_file(&dev->dev, &dev_attr_mode);
+01082         error = device_create_file(&dev->dev, &dev_attr_hnpcapable);
+01083         error = device_create_file(&dev->dev, &dev_attr_srpcapable);
+01084         error = device_create_file(&dev->dev, &dev_attr_hsic_connect);
+01085         error = device_create_file(&dev->dev, &dev_attr_inv_sel_hsic);
+01086         error = device_create_file(&dev->dev, &dev_attr_hnp);
+01087         error = device_create_file(&dev->dev, &dev_attr_srp);
+01088         error = device_create_file(&dev->dev, &dev_attr_buspower);
+01089         error = device_create_file(&dev->dev, &dev_attr_bussuspend);
+01090         error = device_create_file(&dev->dev, &dev_attr_busconnected);
+01091         error = device_create_file(&dev->dev, &dev_attr_gotgctl);
+01092         error = device_create_file(&dev->dev, &dev_attr_gusbcfg);
+01093         error = device_create_file(&dev->dev, &dev_attr_grxfsiz);
+01094         error = device_create_file(&dev->dev, &dev_attr_gnptxfsiz);
+01095         error = device_create_file(&dev->dev, &dev_attr_gpvndctl);
+01096         error = device_create_file(&dev->dev, &dev_attr_ggpio);
+01097         error = device_create_file(&dev->dev, &dev_attr_guid);
+01098         error = device_create_file(&dev->dev, &dev_attr_gsnpsid);
+01099         error = device_create_file(&dev->dev, &dev_attr_devspeed);
+01100         error = device_create_file(&dev->dev, &dev_attr_enumspeed);
+01101         error = device_create_file(&dev->dev, &dev_attr_hptxfsiz);
+01102         error = device_create_file(&dev->dev, &dev_attr_hprt0);
+01103         error = device_create_file(&dev->dev, &dev_attr_remote_wakeup);
+01104         error = device_create_file(&dev->dev, &dev_attr_regdump);
+01105         error = device_create_file(&dev->dev, &dev_attr_spramdump);
+01106         error = device_create_file(&dev->dev, &dev_attr_hcddump);
+01107         error = device_create_file(&dev->dev, &dev_attr_hcd_frrem);
+01108         error = device_create_file(&dev->dev, &dev_attr_rd_reg_test);
+01109         error = device_create_file(&dev->dev, &dev_attr_wr_reg_test);
+01110 #ifdef CONFIG_USB_DWC_OTG_LPM
+01111         error = device_create_file(&dev->dev, &dev_attr_lpm_response);
+01112         error = device_create_file(&dev->dev, &dev_attr_sleep_status);
+01113 #endif
+01114 }
+01115 
+01119 void dwc_otg_attr_remove (
+01120 #ifdef LM_INTERFACE
+01121         struct lm_device *dev
+01122 #elif  PCI_INTERFACE
+01123         struct pci_dev *dev
+01124 #endif
+01125        )
+01126 
+01127 {
+01128         device_remove_file(&dev->dev, &dev_attr_regoffset);
+01129         device_remove_file(&dev->dev, &dev_attr_regvalue);
+01130         device_remove_file(&dev->dev, &dev_attr_mode);
+01131         device_remove_file(&dev->dev, &dev_attr_hnpcapable);
+01132         device_remove_file(&dev->dev, &dev_attr_srpcapable);
+01133         device_remove_file(&dev->dev, &dev_attr_hsic_connect);
+01134         device_remove_file(&dev->dev, &dev_attr_inv_sel_hsic);
+01135         device_remove_file(&dev->dev, &dev_attr_hnp);
+01136         device_remove_file(&dev->dev, &dev_attr_srp);
+01137         device_remove_file(&dev->dev, &dev_attr_buspower);
+01138         device_remove_file(&dev->dev, &dev_attr_bussuspend);
+01139         device_remove_file(&dev->dev, &dev_attr_busconnected);
+01140         device_remove_file(&dev->dev, &dev_attr_gotgctl);
+01141         device_remove_file(&dev->dev, &dev_attr_gusbcfg);
+01142         device_remove_file(&dev->dev, &dev_attr_grxfsiz);
+01143         device_remove_file(&dev->dev, &dev_attr_gnptxfsiz);
+01144         device_remove_file(&dev->dev, &dev_attr_gpvndctl);
+01145         device_remove_file(&dev->dev, &dev_attr_ggpio);
+01146         device_remove_file(&dev->dev, &dev_attr_guid);
+01147         device_remove_file(&dev->dev, &dev_attr_gsnpsid);
+01148         device_remove_file(&dev->dev, &dev_attr_devspeed);
+01149         device_remove_file(&dev->dev, &dev_attr_enumspeed);
+01150         device_remove_file(&dev->dev, &dev_attr_hptxfsiz);
+01151         device_remove_file(&dev->dev, &dev_attr_hprt0);
+01152         device_remove_file(&dev->dev, &dev_attr_remote_wakeup);
+01153         device_remove_file(&dev->dev, &dev_attr_regdump);
+01154         device_remove_file(&dev->dev, &dev_attr_spramdump);
+01155         device_remove_file(&dev->dev, &dev_attr_hcddump);
+01156         device_remove_file(&dev->dev, &dev_attr_hcd_frrem);
+01157         device_remove_file(&dev->dev, &dev_attr_rd_reg_test);
+01158         device_remove_file(&dev->dev, &dev_attr_wr_reg_test);
+01159 #ifdef CONFIG_USB_DWC_OTG_LPM
+01160         device_remove_file(&dev->dev, &dev_attr_lpm_response);
+01161         device_remove_file(&dev->dev, &dev_attr_sleep_status);
+01162 #endif
+01163 }
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__attr_8c.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__attr_8c.html new file mode 100644 index 000000000000..eafdd832cad6 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__attr_8c.html @@ -0,0 +1,485 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_attr.c File Reference + + + + + + +

dwc_otg_attr.c File Reference

The diagnostic interface will provide access to the controller for bringing up the hardware and testing. More... +

+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/stat.h>
+#include <linux/version.h>
+#include <linux/param.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <asm/io.h>
+#include "dwc_os.h"
+#include "dwc_otg_driver.h"
+#include "dwc_otg_attr.h"
+#include "dwc_otg_core_if.h"
+#include "dwc_otg_pcd_if.h"
+#include "dwc_otg_hcd_if.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Functions for Show/Store of Attributes

+#define RW_REG_COUNT   10000000
 Displays the time required to read the GNPTXFSIZ register many times (the output shows the number of times the register is read).
+#define MSEC_PER_JIFFIE   1000/HZ
+static ssize_t regoffset_show (struct device *_dev, struct device_attribute *attr, char *buf)
 Show the register offset of the Register Access.
+static ssize_t regoffset_store (struct device *_dev, struct device_attribute *attr, const char *buf, size_t count)
 Set the register offset for the next Register Access Read/Write.
+static ssize_t regvalue_show (struct device *_dev, struct device_attribute *attr, char *buf)
 Show the value of the register at the offset in the reg_offset attribute.
+static ssize_t regvalue_store (struct device *_dev, struct device_attribute *attr, const char *buf, size_t count)
 Store the value in the register at the offset in the reg_offset attribute.
DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW (mode,"Mode")
+static ssize_t hnp_store (struct device *_dev, struct device_attribute *attr, const char *buf, size_t count)
 Set the HNP Request bit.
+static ssize_t srp_show (struct device *_dev, struct device_attribute *attr, char *buf)
 Show the SRP status bit.
+static ssize_t srp_store (struct device *_dev, struct device_attribute *attr, const char *buf, size_t count)
 Set the SRP Request bit.
+static ssize_t buspower_show (struct device *_dev, struct device_attribute *attr, char *buf)
 Show the Bus Power status.
+static ssize_t buspower_store (struct device *_dev, struct device_attribute *attr, const char *buf, size_t count)
 Set the Bus Power status.
+static ssize_t bussuspend_show (struct device *_dev, struct device_attribute *attr, char *buf)
 Show the Bus Suspend status.
+static ssize_t bussuspend_store (struct device *_dev, struct device_attribute *attr, const char *buf, size_t count)
 Set the Bus Suspend status.
+static ssize_t remote_wakeup_show (struct device *_dev, struct device_attribute *attr, char *buf)
 Show the status of Remote Wakeup.
static ssize_t remote_wakeup_store (struct device *_dev, struct device_attribute *attr, const char *buf, size_t count)
 Initiate a remote wakeup of the host.
+static ssize_t regdump_show (struct device *_dev, struct device_attribute *attr, char *buf)
 Dump global registers and either host or device registers (depending on the current mode of the core).
+S_IRUGO static ssize_t spramdump_show (struct device *_dev, struct device_attribute *attr, char *buf)
 Dump global registers and either host or device registers (depending on the current mode of the core).
+S_IRUGO static ssize_t hcddump_show (struct device *_dev, struct device_attribute *attr, char *buf)
 Dump the current hcd state.
S_IRUGO static ssize_t hcd_frrem_show (struct device *_dev, struct device_attribute *attr, char *buf)
 Dump the average frame remaining at SOF.
+static ssize_t rd_reg_test_show (struct device *_dev, struct device_attribute *attr, char *buf)
+S_IRUGO static ssize_t wr_reg_test_show (struct device *_dev, struct device_attribute *attr, char *buf)
 Displays the time required to write the GNPTXFSIZ register many times (the output shows the number of times the register is written).
regoffset
+S_IRUGO S_IWUSR
+S_IRUGO regoffset_show
+S_IRUGO regoffset_store
regvalue
+S_IRUGO S_IWUSR
+S_IRUGO regvalue_show
+S_IRUGO regvalue_store
hnp
hnp_show
hnp_store
srp
srp_show
srp_store
buspower
buspower_show
buspower_store
bussuspend
bussuspend_show
bussuspend_store
remote_wakeup
+S_IRUGO S_IWUSR
+S_IRUGO remote_wakeup_show
+S_IRUGO remote_wakeup_store
regdump
+S_IRUGO S_IWUSR
+S_IRUGO regdump_show
spramdump
+S_IRUGO S_IWUSR
+S_IRUGO spramdump_show
hcddump
+S_IRUGO S_IWUSR
+S_IRUGO hcddump_show
hcd_frrem
+S_IRUGO S_IWUSR
+S_IRUGO hcd_frrem_show
rd_reg_test
+S_IRUGO S_IWUSR
+S_IRUGO rd_reg_test_show
wr_reg_test
+S_IRUGO S_IWUSR
+S_IRUGO wr_reg_test_show

Defines

#define DWC_OTG_DEVICE_ATTR_BITFIELD_RW(_otg_attr_name_, _string_)
#define DWC_OTG_DEVICE_ATTR_BITFIELD_RO(_otg_attr_name_, _string_)
#define DWC_OTG_DEVICE_ATTR_REG32_RW(_otg_attr_name_, _addr_, _string_)
#define DWC_OTG_DEVICE_ATTR_REG32_RO(_otg_attr_name_, _addr_, _string_)

Functions

+S_IRUGO void dwc_otg_attr_create ()
 Create the device files.
+void dwc_otg_attr_remove ()
 Remove the device files.
+


Detailed Description

+The diagnostic interface will provide access to the controller for bringing up the hardware and testing. +

+The Linux driver attributes feature will be used to provide the Linux Diagnostic Interface. These attributes are accessed through sysfs. +

+Definition in file dwc_otg_attr.c.


Define Documentation

+ +
+
+ + + + + + + + + + + + +
#define DWC_OTG_DEVICE_ATTR_BITFIELD_RW (_otg_attr_name_,
_string_   ) 
+
+
+ +

+Value:

DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
+DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \
+DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
+
+

+Definition at line 405 of file dwc_otg_attr.c. +

+

+ +

+
+ + + + + + + + + + + + +
#define DWC_OTG_DEVICE_ATTR_BITFIELD_RO (_otg_attr_name_,
_string_   ) 
+
+
+ +

+Value:

DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \
+DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
+
+

+Definition at line 410 of file dwc_otg_attr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_OTG_DEVICE_ATTR_REG32_RW (_otg_attr_name_,
_addr_,
_string_   ) 
+
+
+ +

+Value:

DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
+DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \
+DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store);
+
+

+Definition at line 414 of file dwc_otg_attr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + +
#define DWC_OTG_DEVICE_ATTR_REG32_RO (_otg_attr_name_,
_addr_,
_string_   ) 
+
+
+ +

+Value:

DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \
+DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL);
+
+

+Definition at line 419 of file dwc_otg_attr.c. +

+

+


Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static ssize_t remote_wakeup_store (struct device *  _dev,
struct device_attribute *  attr,
const char *  buf,
size_t  count 
) [static]
+
+
+ +

+Initiate a remote wakeup of the host. +

+The Device control register Remote Wakeup Signal bit is written if the PCD Remote wakeup enable flag is set. +

+Definition at line 773 of file dwc_otg_attr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
S_IRUGO static ssize_t hcd_frrem_show (struct device *  _dev,
struct device_attribute *  attr,
char *  buf 
) [static]
+
+
+ +

+Dump the average frame remaining at SOF. +

+This can be used to determine average interrupt latency. Frame remaining is also shown for start transfer and two additional sample points. +

+Definition at line 872 of file dwc_otg_attr.c. +

+

+


Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__attr_8h-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__attr_8h-source.html new file mode 100644 index 000000000000..59c3fd3b4f36 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__attr_8h-source.html @@ -0,0 +1,105 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_attr.h Source File + + + + + + +

dwc_otg_attr.h

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.h $
+00003  * $Revision: #11 $
+00004  * $Date: 2009/04/03 $
+00005  * $Change: 1225160 $
+00006  *
+00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009  * otherwise expressly agreed to in writing between Synopsys and you.
+00010  * 
+00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012  * any End User Software License Agreement or Agreement for Licensed Product
+00013  * with Synopsys or any supplement thereto. You are permitted to use and
+00014  * redistribute this Software in source and binary forms, with or without
+00015  * modification, provided that redistributions of source code must retain this
+00016  * notice. You may not view, use, disclose, copy or distribute this file or
+00017  * any information contained herein except pursuant to this license grant from
+00018  * Synopsys. If you do not agree with this notice, including the disclaimer
+00019  * below, then you are not authorized to use the Software.
+00020  * 
+00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031  * DAMAGE.
+00032  * ========================================================================== */
+00033 
+00034 #if !defined(__DWC_OTG_ATTR_H__)
+00035 #define __DWC_OTG_ATTR_H__
+00036 
+00040 extern struct device_attribute dev_attr_regoffset;
+00041 extern struct device_attribute dev_attr_regvalue;
+00042 
+00043 extern struct device_attribute dev_attr_mode;
+00044 extern struct device_attribute dev_attr_hnpcapable;
+00045 extern struct device_attribute dev_attr_srpcapable;
+00046 extern struct device_attribute dev_attr_hnp;
+00047 extern struct device_attribute dev_attr_srp;
+00048 extern struct device_attribute dev_attr_buspower;
+00049 extern struct device_attribute dev_attr_bussuspend;
+00050 extern struct device_attribute dev_attr_busconnected;
+00051 extern struct device_attribute dev_attr_gotgctl;
+00052 extern struct device_attribute dev_attr_gusbcfg;
+00053 extern struct device_attribute dev_attr_grxfsiz;
+00054 extern struct device_attribute dev_attr_gnptxfsiz;
+00055 extern struct device_attribute dev_attr_gpvndctl;
+00056 extern struct device_attribute dev_attr_ggpio;
+00057 extern struct device_attribute dev_attr_guid;
+00058 extern struct device_attribute dev_attr_gsnpsid;
+00059 extern struct device_attribute dev_attr_devspeed;
+00060 extern struct device_attribute dev_attr_enumspeed;
+00061 extern struct device_attribute dev_attr_hptxfsiz;
+00062 extern struct device_attribute dev_attr_hprt0;
+00063 #ifdef CONFIG_USB_DWC_OTG_LPM
+00064 extern struct device_attribute dev_attr_lpm_response;
+00065 extern struct device_attribute dev_attr_sleep_local_dev;
+00066 extern struct device_attribute devi_attr_sleep_status;
+00067 #endif
+00068 
+00069 void dwc_otg_attr_create (
+00070 #ifdef LM_INTERFACE
+00071         struct lm_device *dev
+00072 #elif  PCI_INTERFACE
+00073         struct pci_dev *dev
+00074 #endif
+00075         );
+00076 
+00077 void dwc_otg_attr_remove (
+00078 #ifdef LM_INTERFACE
+00079         struct lm_device *dev
+00080 #elif  PCI_INTERFACE
+00081         struct pci_dev *dev
+00082 #endif
+00083         );
+00084 #endif
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__attr_8h.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__attr_8h.html new file mode 100644 index 000000000000..2ef83afdf61e --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__attr_8h.html @@ -0,0 +1,116 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_attr.h File Reference + + + + + + +

dwc_otg_attr.h File Reference

This file contains the interface to the Linux device attributes. More... +

+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Defines

+#define __DWC_OTG_ATTR_H__

Functions

+void dwc_otg_attr_create ()
 Create the device files.
+void dwc_otg_attr_remove ()
 Remove the device files.

Variables

+device_attribute dev_attr_regoffset
+device_attribute dev_attr_regvalue
+device_attribute dev_attr_mode
+device_attribute dev_attr_hnpcapable
+device_attribute dev_attr_srpcapable
+device_attribute dev_attr_hnp
+device_attribute dev_attr_srp
+device_attribute dev_attr_buspower
+device_attribute dev_attr_bussuspend
+device_attribute dev_attr_busconnected
+device_attribute dev_attr_gotgctl
+device_attribute dev_attr_gusbcfg
+device_attribute dev_attr_grxfsiz
+device_attribute dev_attr_gnptxfsiz
+device_attribute dev_attr_gpvndctl
+device_attribute dev_attr_ggpio
+device_attribute dev_attr_guid
+device_attribute dev_attr_gsnpsid
+device_attribute dev_attr_devspeed
+device_attribute dev_attr_enumspeed
+device_attribute dev_attr_hptxfsiz
+device_attribute dev_attr_hprt0
+


Detailed Description

+This file contains the interface to the Linux device attributes. +

+ +

+Definition in file dwc_otg_attr.h.


Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cfi_8c-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cfi_8c-source.html new file mode 100644 index 000000000000..df7d3d38c565 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cfi_8c-source.html @@ -0,0 +1,1724 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_cfi.c Source File + + + + + + +

dwc_otg_cfi.c

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00003  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00004  * otherwise expressly agreed to in writing between Synopsys and you.
+00005  * 
+00006  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00007  * any End User Software License Agreement or Agreement for Licensed Product
+00008  * with Synopsys or any supplement thereto. You are permitted to use and
+00009  * redistribute this Software in source and binary forms, with or without
+00010  * modification, provided that redistributions of source code must retain this
+00011  * notice. You may not view, use, disclose, copy or distribute this file or
+00012  * any information contained herein except pursuant to this license grant from
+00013  * Synopsys. If you do not agree with this notice, including the disclaimer
+00014  * below, then you are not authorized to use the Software.
+00015  * 
+00016  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00017  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00018  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00019  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00020  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00021  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00022  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00023  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00024  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00025  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00026  * DAMAGE.
+00027  * ========================================================================== */
+00028 
+00034 #ifdef DWC_UTE_CFI
+00035 
+00036 #include "dwc_otg_pcd.h"
+00037 #include "dwc_otg_cfi.h"
+00038 
+00040 #define DWC_CONSTANT_CPU_TO_LE16(x) (x)
+00041 
+00042 extern dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex);
+00043 
+00044 static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen);
+00045 static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
+00046                                  struct dwc_otg_pcd *pcd,
+00047                                  struct cfi_usb_ctrlrequest *ctrl_req);
+00048 static int cfi_set_feature_value(struct dwc_otg_pcd *pcd);
+00049 static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
+00050                              struct cfi_usb_ctrlrequest *req);
+00051 static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
+00052                                  struct cfi_usb_ctrlrequest *req);
+00053 static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
+00054                                 struct cfi_usb_ctrlrequest *req);
+00055 static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
+00056                              struct cfi_usb_ctrlrequest *req);
+00057 static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep);
+00058 
+00059 static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if);
+00060 static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue);
+00061 static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue);
+00062 
+00063 static uint8_t resize_fifos(dwc_otg_core_if_t * core_if);
+00064 
+00066 static cfi_all_features_header_t all_props_desc_header = {
+00067         .wVersion = DWC_CONSTANT_CPU_TO_LE16(0x100),
+00068         .wCoreID = DWC_CONSTANT_CPU_TO_LE16(CFI_CORE_ID_OTG),
+00069         .wNumFeatures = DWC_CONSTANT_CPU_TO_LE16(9),
+00070 };
+00071 
+00073 static cfi_feature_desc_header_t prop_descs[] = {
+00074 
+00075         /* FT_ID_DMA_MODE */
+00076         {
+00077          .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_MODE),
+00078          .bmAttributes = CFI_FEATURE_ATTR_RW,
+00079          .wDataLength = DWC_CONSTANT_CPU_TO_LE16(1),
+00080          },
+00081 
+00082         /* FT_ID_DMA_BUFFER_SETUP */
+00083         {
+00084          .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFFER_SETUP),
+00085          .bmAttributes = CFI_FEATURE_ATTR_RW,
+00086          .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
+00087          },
+00088 
+00089         /* FT_ID_DMA_BUFF_ALIGN */
+00090         {
+00091          .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFF_ALIGN),
+00092          .bmAttributes = CFI_FEATURE_ATTR_RW,
+00093          .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
+00094          },
+00095 
+00096         /* FT_ID_DMA_CONCAT_SETUP */
+00097         {
+00098          .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CONCAT_SETUP),
+00099          .bmAttributes = CFI_FEATURE_ATTR_RW,
+00100          //.wDataLength  = DWC_CONSTANT_CPU_TO_LE16(6),
+00101          },
+00102 
+00103         /* FT_ID_DMA_CIRCULAR */
+00104         {
+00105          .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CIRCULAR),
+00106          .bmAttributes = CFI_FEATURE_ATTR_RW,
+00107          .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
+00108          },
+00109 
+00110         /* FT_ID_THRESHOLD_SETUP */
+00111         {
+00112          .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_THRESHOLD_SETUP),
+00113          .bmAttributes = CFI_FEATURE_ATTR_RW,
+00114          .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6),
+00115          },
+00116 
+00117         /* FT_ID_DFIFO_DEPTH */
+00118         {
+00119          .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DFIFO_DEPTH),
+00120          .bmAttributes = CFI_FEATURE_ATTR_RO,
+00121          .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
+00122          },
+00123 
+00124         /* FT_ID_TX_FIFO_DEPTH */
+00125         {
+00126          .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_TX_FIFO_DEPTH),
+00127          .bmAttributes = CFI_FEATURE_ATTR_RW,
+00128          .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
+00129          },
+00130 
+00131         /* FT_ID_RX_FIFO_DEPTH */
+00132         {
+00133          .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_RX_FIFO_DEPTH),
+00134          .bmAttributes = CFI_FEATURE_ATTR_RW,
+00135          .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2),
+00136          }
+00137 };
+00138 
+00140 cfi_string_t prop_name_table[] = {
+00141         {FT_ID_DMA_MODE, "dma_mode"},
+00142         {FT_ID_DMA_BUFFER_SETUP, "buffer_setup"},
+00143         {FT_ID_DMA_BUFF_ALIGN, "buffer_align"},
+00144         {FT_ID_DMA_CONCAT_SETUP, "concat_setup"},
+00145         {FT_ID_DMA_CIRCULAR, "buffer_circular"},
+00146         {FT_ID_THRESHOLD_SETUP, "threshold_setup"},
+00147         {FT_ID_DFIFO_DEPTH, "dfifo_depth"},
+00148         {FT_ID_TX_FIFO_DEPTH, "txfifo_depth"},
+00149         {FT_ID_RX_FIFO_DEPTH, "rxfifo_depth"},
+00150         {}
+00151 };
+00152 
+00153 /************************************************************************/
+00154 
+00160 const uint8_t *get_prop_name(uint16_t prop_id, int *len)
+00161 {
+00162         cfi_string_t *pstr;
+00163         *len = 0;
+00164 
+00165         for (pstr = prop_name_table; pstr && pstr->s; pstr++) {
+00166                 if (pstr->id == prop_id) {
+00167                         *len = DWC_STRLEN(pstr->s);
+00168                         return pstr->s;
+00169                 }
+00170         }
+00171         return NULL;
+00172 }
+00173 
+00179 int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl)
+00180 {
+00181         int retval = 0;
+00182         dwc_otg_pcd_ep_t *ep = NULL;
+00183         cfiobject_t *cfi = pcd->cfi;
+00184         struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
+00185         uint16_t wLen = DWC_LE16_TO_CPU(&ctrl->wLength);
+00186         uint16_t wValue = DWC_LE16_TO_CPU(&ctrl->wValue);
+00187         uint16_t wIndex = DWC_LE16_TO_CPU(&ctrl->wIndex);
+00188         uint32_t regaddr = 0;
+00189         uint32_t regval = 0;
+00190 
+00191         /* Save this Control Request in the CFI object. 
+00192          * The data field will be assigned in the data stage completion CB function.
+00193          */
+00194         cfi->ctrl_req = *ctrl;
+00195         cfi->ctrl_req.data = NULL;
+00196 
+00197         cfi->need_gadget_att = 0;
+00198         cfi->need_status_in_complete = 0;
+00199 
+00200         switch (ctrl->bRequest) {
+00201         case VEN_CORE_GET_FEATURES:
+00202                 retval = cfi_core_features_buf(cfi->buf_in.buf, CFI_IN_BUF_LEN);
+00203                 if (retval >= 0) {
+00204                         //dump_msg(cfi->buf_in.buf, retval);
+00205                         ep = &pcd->ep0;
+00206 
+00207                         retval = min((uint16_t) retval, wLen);
+00208                         /* Transfer this buffer to the host through the EP0-IN EP */
+00209                         ep->dwc_ep.dma_addr = cfi->buf_in.addr;
+00210                         ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
+00211                         ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
+00212                         ep->dwc_ep.xfer_len = retval;
+00213                         ep->dwc_ep.xfer_count = 0;
+00214                         ep->dwc_ep.sent_zlp = 0;
+00215                         ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
+00216 
+00217                         pcd->ep0_pending = 1;
+00218                         dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
+00219                 }
+00220                 retval = 0;
+00221                 break;
+00222 
+00223         case VEN_CORE_GET_FEATURE:
+00224                 CFI_INFO("VEN_CORE_GET_FEATURE\n");
+00225                 retval = cfi_get_feature_value(cfi->buf_in.buf, CFI_IN_BUF_LEN,
+00226                                                pcd, ctrl);
+00227                 if (retval >= 0) {
+00228                         ep = &pcd->ep0;
+00229 
+00230                         retval = min((uint16_t) retval, wLen);
+00231                         /* Transfer this buffer to the host through the EP0-IN EP */
+00232                         ep->dwc_ep.dma_addr = cfi->buf_in.addr;
+00233                         ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
+00234                         ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
+00235                         ep->dwc_ep.xfer_len = retval;
+00236                         ep->dwc_ep.xfer_count = 0;
+00237                         ep->dwc_ep.sent_zlp = 0;
+00238                         ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
+00239 
+00240                         pcd->ep0_pending = 1;
+00241                         dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
+00242                 }
+00243                 CFI_INFO("VEN_CORE_GET_FEATURE=%d\n", retval);
+00244                 dump_msg(cfi->buf_in.buf, retval);
+00245                 break;
+00246 
+00247         case VEN_CORE_SET_FEATURE:
+00248                 CFI_INFO("VEN_CORE_SET_FEATURE\n");
+00249                 /* Set up an XFER to get the data stage of the control request,
+00250                  * which is the new value of the feature to be modified.
+00251                  */
+00252                 ep = &pcd->ep0;
+00253                 ep->dwc_ep.is_in = 0;
+00254                 ep->dwc_ep.dma_addr = cfi->buf_out.addr;
+00255                 ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
+00256                 ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
+00257                 ep->dwc_ep.xfer_len = wLen;
+00258                 ep->dwc_ep.xfer_count = 0;
+00259                 ep->dwc_ep.sent_zlp = 0;
+00260                 ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
+00261 
+00262                 pcd->ep0_pending = 1;
+00263                 /* Read the control write's data stage */
+00264                 dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
+00265                 retval = 0;
+00266                 break;
+00267 
+00268         case VEN_CORE_RESET_FEATURES:
+00269                 CFI_INFO("VEN_CORE_RESET_FEATURES\n");
+00270                 cfi->need_gadget_att = 1;
+00271                 cfi->need_status_in_complete = 1;
+00272                 retval = cfi_preproc_reset(pcd, ctrl);
+00273                 CFI_INFO("VEN_CORE_RESET_FEATURES = (%d)\n", retval);
+00274                 break;
+00275 
+00276         case VEN_CORE_ACTIVATE_FEATURES:
+00277                 CFI_INFO("VEN_CORE_ACTIVATE_FEATURES\n");
+00278                 break;
+00279 
+00280         case VEN_CORE_READ_REGISTER:
+00281                 CFI_INFO("VEN_CORE_READ_REGISTER\n");
+00282                 /* wValue optionally contains the HI WORD of the register offset and
+00283                  * wIndex contains the LOW WORD of the register offset 
+00284                  */
+00285                 if (wValue == 0) {
+00286                         /* @TODO - MAS - fix the access to the base field */
+00287                         regaddr = 0;
+00288                         //regaddr = (uint32_t) pcd->otg_dev->base;
+00289                         //GET_CORE_IF(pcd)->co
+00290                         regaddr |= wIndex;
+00291                 } else {
+00292                         regaddr = (wValue << 16) | wIndex;
+00293                 }
+00294 
+00295                 /* Read a 32-bit value of the memory at the regaddr */
+00296                 regval = dwc_read_reg32((uint32_t *) regaddr);
+00297 
+00298                 ep = &pcd->ep0;
+00299                 dwc_memcpy(cfi->buf_in.buf, &regval, sizeof(uint32_t));
+00300                 ep->dwc_ep.is_in = 1;
+00301                 ep->dwc_ep.dma_addr = cfi->buf_in.addr;
+00302                 ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf;
+00303                 ep->dwc_ep.xfer_buff = cfi->buf_in.buf;
+00304                 ep->dwc_ep.xfer_len = wLen;
+00305                 ep->dwc_ep.xfer_count = 0;
+00306                 ep->dwc_ep.sent_zlp = 0;
+00307                 ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
+00308 
+00309                 pcd->ep0_pending = 1;
+00310                 dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
+00311                 cfi->need_gadget_att = 0;
+00312                 retval = 0;
+00313                 break;
+00314 
+00315         case VEN_CORE_WRITE_REGISTER:
+00316                 CFI_INFO("VEN_CORE_WRITE_REGISTER\n");
+00317                 /* Set up an XFER to get the data stage of the control request,
+00318                  * which is the new value of the register to be modified.
+00319                  */
+00320                 ep = &pcd->ep0;
+00321                 ep->dwc_ep.is_in = 0;
+00322                 ep->dwc_ep.dma_addr = cfi->buf_out.addr;
+00323                 ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf;
+00324                 ep->dwc_ep.xfer_buff = cfi->buf_out.buf;
+00325                 ep->dwc_ep.xfer_len = wLen;
+00326                 ep->dwc_ep.xfer_count = 0;
+00327                 ep->dwc_ep.sent_zlp = 0;
+00328                 ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
+00329 
+00330                 pcd->ep0_pending = 1;
+00331                 /* Read the control write's data stage */
+00332                 dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep);
+00333                 retval = 0;
+00334                 break;
+00335 
+00336         default:
+00337                 retval = -DWC_E_NOT_SUPPORTED;
+00338                 break;
+00339         }
+00340 
+00341         return retval;
+00342 }
+00343 
+00355 static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen)
+00356 {
+00357         cfi_feature_desc_header_t *prop_hdr = prop_descs;
+00358         cfi_feature_desc_header_t *prop;
+00359         cfi_all_features_header_t *all_props_hdr = &all_props_desc_header;
+00360         cfi_all_features_header_t *tmp;
+00361         uint8_t *tmpbuf = buf;
+00362         const uint8_t *pname = NULL;
+00363         int i, j, namelen = 0, totlen;
+00364 
+00365         /* Prepare and copy the core features into the buffer */
+00366         CFI_INFO("%s:\n", __func__);
+00367 
+00368         tmp = (cfi_all_features_header_t *) tmpbuf;
+00369         *tmp = *all_props_hdr;
+00370         tmpbuf += CFI_ALL_FEATURES_HDR_LEN;
+00371 
+00372         j = sizeof(prop_descs) / sizeof(cfi_all_features_header_t);
+00373         for (i = 0; i < j; i++, prop_hdr++) {
+00374                 pname = get_prop_name(prop_hdr->wFeatureID, &namelen);
+00375                 prop = (cfi_feature_desc_header_t *) tmpbuf;
+00376                 *prop = *prop_hdr;
+00377 
+00378                 prop->bNameLen = namelen;
+00379                 prop->wLength =
+00380                     DWC_CONSTANT_CPU_TO_LE16(CFI_FEATURE_DESC_HDR_LEN +
+00381                                              namelen);
+00382 
+00383                 tmpbuf += CFI_FEATURE_DESC_HDR_LEN;
+00384                 dwc_memcpy(tmpbuf, pname, namelen);
+00385                 tmpbuf += namelen;
+00386         }
+00387 
+00388         totlen = tmpbuf - buf;
+00389 
+00390         if (totlen > 0) {
+00391                 tmp = (cfi_all_features_header_t *) buf;
+00392                 tmp->wTotalLen = DWC_CONSTANT_CPU_TO_LE16(totlen);
+00393         }
+00394 
+00395         return totlen;
+00396 }
+00397 
+00401 static void cfi_release(cfiobject_t * cfiobj)
+00402 {
+00403         cfi_ep_t *cfiep;
+00404         dwc_list_link_t *tmp;
+00405 
+00406         CFI_INFO("%s\n", __func__);
+00407 
+00408         if (cfiobj->buf_in.buf) {
+00409                 dwc_dma_free(CFI_IN_BUF_LEN, cfiobj->buf_in.buf,
+00410                              cfiobj->buf_in.addr);
+00411                 cfiobj->buf_in.buf = NULL;
+00412         }
+00413 
+00414         if (cfiobj->buf_out.buf) {
+00415                 dwc_dma_free(CFI_OUT_BUF_LEN, cfiobj->buf_out.buf,
+00416                              cfiobj->buf_out.addr);
+00417                 cfiobj->buf_out.buf = NULL;
+00418         }
+00419 
+00420         /* Free the Buffer Setup values for each EP */
+00421         //list_for_each_entry(cfiep, &cfiobj->active_eps, lh) {
+00422         DWC_LIST_FOREACH(tmp, &cfiobj->active_eps) {
+00423                 cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
+00424                 cfi_free_ep_bs_dyn_data(cfiep);
+00425         }
+00426 }
+00427 
+00431 static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep)
+00432 {
+00433         if (cfiep->bm_sg) {
+00434                 dwc_free(cfiep->bm_sg);
+00435                 cfiep->bm_sg = NULL;
+00436         }
+00437 
+00438         if (cfiep->bm_align) {
+00439                 dwc_free(cfiep->bm_align);
+00440                 cfiep->bm_align = NULL;
+00441         }
+00442 
+00443         if (cfiep->bm_concat) {
+00444                 if (NULL != cfiep->bm_concat->wTxBytes) {
+00445                         dwc_free(cfiep->bm_concat->wTxBytes);
+00446                         cfiep->bm_concat->wTxBytes = NULL;
+00447                 }
+00448                 dwc_free(cfiep->bm_concat);
+00449                 cfiep->bm_concat = NULL;
+00450         }
+00451 }
+00452 
+00458 static int cfi_ep_init_defaults(struct dwc_otg_pcd *pcd, cfi_ep_t * cfiep)
+00459 {
+00460         int retval = 0;
+00461 
+00462         cfiep->bm_sg = dwc_alloc(sizeof(ddma_sg_buffer_setup_t));
+00463         if (NULL == cfiep->bm_sg) {
+00464                 CFI_INFO("Failed to allocate memory for SG feature value\n");
+00465                 return -DWC_E_NO_MEMORY;
+00466         }
+00467         dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
+00468 
+00469         /* For the Concatenation feature's default value we do not allocate
+00470          * memory for the wTxBytes field - it will be done in the set_feature_value
+00471          * request handler.
+00472          */
+00473         cfiep->bm_concat = dwc_alloc(sizeof(ddma_concat_buffer_setup_t));
+00474         if (NULL == cfiep->bm_concat) {
+00475                 CFI_INFO
+00476                     ("Failed to allocate memory for CONCATENATION feature value\n");
+00477                 dwc_free(cfiep->bm_sg);
+00478                 return -DWC_E_NO_MEMORY;
+00479         }
+00480         dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
+00481 
+00482         cfiep->bm_align = dwc_alloc(sizeof(ddma_align_buffer_setup_t));
+00483         if (NULL == cfiep->bm_align) {
+00484                 CFI_INFO
+00485                     ("Failed to allocate memory for Alignment feature value\n");
+00486                 dwc_free(cfiep->bm_sg);
+00487                 dwc_free(cfiep->bm_concat);
+00488                 return -DWC_E_NO_MEMORY;
+00489         }
+00490         dwc_memset(cfiep->bm_align, 0, sizeof(ddma_align_buffer_setup_t));
+00491 
+00492         return retval;
+00493 }
+00494 
+00506 static int cfi_ep_enable(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
+00507                          struct dwc_otg_pcd_ep *ep)
+00508 {
+00509         cfi_ep_t *cfiep;
+00510         int retval = -DWC_E_NOT_SUPPORTED;
+00511 
+00512         CFI_INFO("%s: epname=%s; epnum=0x%02x\n", __func__,
+00513                  "EP_" /*ep->ep.name */ , ep->desc->bEndpointAddress);
+00514         /* MAS - Check whether this endpoint already is in the list */
+00515         cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
+00516 
+00517         if (NULL == cfiep) {
+00518                 /* Allocate a cfi_ep_t object */
+00519                 cfiep = dwc_alloc(sizeof(cfi_ep_t));
+00520                 if (NULL == cfiep) {
+00521                         CFI_INFO
+00522                             ("Unable to allocate memory for <cfiep> in function %s\n",
+00523                              __func__);
+00524                         return -DWC_E_NO_MEMORY;
+00525                 }
+00526                 dwc_memset(cfiep, 0, sizeof(cfi_ep_t));
+00527 
+00528                 /* Save the dwc_otg_pcd_ep pointer in the cfiep object */
+00529                 cfiep->ep = ep;
+00530 
+00531                 /* Allocate the DMA Descriptors chain of MAX_DMA_DESCS_PER_EP count */
+00532                 ep->dwc_ep.descs =
+00533                     dwc_dma_alloc(MAX_DMA_DESCS_PER_EP *
+00534                                   sizeof(dwc_otg_dma_desc_t),
+00535                                   &ep->dwc_ep.descs_dma_addr);
+00536 
+00537                 if (NULL == ep->dwc_ep.descs) {
+00538                         dwc_free(cfiep);
+00539                         return -DWC_E_NO_MEMORY;
+00540                 }
+00541 
+00542                 DWC_LIST_INIT(&cfiep->lh);
+00543 
+00544                 /* Set the buffer mode to BM_STANDARD. It will be modified 
+00545                  * when building descriptors for a specific buffer mode */
+00546                 ep->dwc_ep.buff_mode = BM_STANDARD;
+00547 
+00548                 /* Create and initialize the default values for this EP's Buffer modes */
+00549                 if ((retval = cfi_ep_init_defaults(pcd, cfiep)) < 0)
+00550                         return retval;
+00551 
+00552                 /* Add the cfi_ep_t object to the CFI object's list of active endpoints */
+00553                 DWC_LIST_INSERT_TAIL(&cfi->active_eps, &cfiep->lh);
+00554                 retval = 0;
+00555         } else {                /* The sought EP already is in the list */
+00556                 CFI_INFO("%s: The sought EP already is in the list\n",
+00557                          __func__);
+00558         }
+00559 
+00560         return retval;
+00561 }
+00562 
+00568 static int cfi_ctrl_write_complete(struct cfiobject *cfi,
+00569                                    struct dwc_otg_pcd *pcd)
+00570 {
+00571         uint32_t addr, reg_value;
+00572         uint16_t wIndex, wValue;
+00573         uint8_t bRequest;
+00574         uint8_t *buf = cfi->buf_out.buf;
+00575         //struct usb_ctrlrequest *ctrl_req = &cfi->ctrl_req_saved;
+00576         struct cfi_usb_ctrlrequest *ctrl_req = &cfi->ctrl_req;
+00577         int retval = -DWC_E_NOT_SUPPORTED;
+00578 
+00579         CFI_INFO("%s\n", __func__);
+00580 
+00581         bRequest = ctrl_req->bRequest;
+00582         wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
+00583         wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
+00584 
+00585         /* 
+00586          * Save the pointer to the data stage in the ctrl_req's <data> field.
+00587          * The request should be already saved in the command stage by now.
+00588          */
+00589         ctrl_req->data = cfi->buf_out.buf;
+00590         cfi->need_status_in_complete = 0;
+00591         cfi->need_gadget_att = 0;
+00592 
+00593         switch (bRequest) {
+00594         case VEN_CORE_WRITE_REGISTER:
+00595                 /* The buffer contains raw data of the new value for the register */
+00596                 reg_value = *((uint32_t *) buf);
+00597                 if (wValue == 0) {
+00598                         addr = 0;
+00599                         //addr = (uint32_t) pcd->otg_dev->base;
+00600                         addr += wIndex;
+00601                 } else {
+00602                         addr = (wValue << 16) | wIndex;
+00603                 }
+00604 
+00605                 //writel(reg_value, addr);
+00606 
+00607                 retval = 0;
+00608                 cfi->need_status_in_complete = 1;
+00609                 break;
+00610 
+00611         case VEN_CORE_SET_FEATURE:
+00612                 /* The buffer contains raw data of the new value of the feature */
+00613                 retval = cfi_set_feature_value(pcd);
+00614                 if (retval < 0)
+00615                         return retval;
+00616 
+00617                 cfi->need_status_in_complete = 1;
+00618                 break;
+00619 
+00620         default:
+00621                 break;
+00622         }
+00623 
+00624         return retval;
+00625 }
+00626 
+00630 static void cfi_build_sg_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
+00631                                dwc_otg_pcd_request_t * req)
+00632 {
+00633         struct dwc_otg_pcd_ep *ep = cfiep->ep;
+00634         ddma_sg_buffer_setup_t *sgval = cfiep->bm_sg;
+00635         struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
+00636         struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
+00637         dma_addr_t buff_addr = req->dma;
+00638         int i;
+00639         uint32_t txsize, off;
+00640 
+00641         txsize = sgval->wSize;
+00642         off = sgval->bOffset;
+00643 
+00644 //      CFI_INFO("%s: %s TXSIZE=0x%08x; OFFSET=0x%08x\n", 
+00645 //              __func__, cfiep->ep->ep.name, txsize, off);
+00646 
+00647         for (i = 0; i < sgval->bCount; i++) {
+00648                 desc->status.b.bs = BS_HOST_BUSY;
+00649                 desc->buf = buff_addr;
+00650                 desc->status.b.l = 0;
+00651                 desc->status.b.ioc = 0;
+00652                 desc->status.b.sp = 0;
+00653                 desc->status.b.bytes = txsize;
+00654                 desc->status.b.bs = BS_HOST_READY;
+00655 
+00656                 /* Set the next address of the buffer */
+00657                 buff_addr += txsize + off;
+00658                 desc_last = desc;
+00659                 desc++;
+00660         }
+00661 
+00662         /* Set the last, ioc and sp bits on the Last DMA Descriptor */
+00663         desc_last->status.b.l = 1;
+00664         desc_last->status.b.ioc = 1;
+00665         desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
+00666         /* Save the last DMA descriptor pointer */
+00667         cfiep->dma_desc_last = desc_last;
+00668         cfiep->desc_count = sgval->bCount;
+00669 }
+00670 
+00674 static void cfi_build_concat_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
+00675                                    dwc_otg_pcd_request_t * req)
+00676 {
+00677         struct dwc_otg_pcd_ep *ep = cfiep->ep;
+00678         ddma_concat_buffer_setup_t *concatval = cfiep->bm_concat;
+00679         struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
+00680         struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs;
+00681         dma_addr_t buff_addr = req->dma;
+00682         int i;
+00683         uint16_t *txsize;
+00684 
+00685         txsize = concatval->wTxBytes;
+00686 
+00687         for (i = 0; i < concatval->hdr.bDescCount; i++) {
+00688                 desc->buf = buff_addr;
+00689                 desc->status.b.bs = BS_HOST_BUSY;
+00690                 desc->status.b.l = 0;
+00691                 desc->status.b.ioc = 0;
+00692                 desc->status.b.sp = 0;
+00693                 desc->status.b.bytes = *txsize;
+00694                 desc->status.b.bs = BS_HOST_READY;
+00695 
+00696                 txsize++;
+00697                 /* Set the next address of the buffer */
+00698                 buff_addr += UGETW(ep->desc->wMaxPacketSize);
+00699                 desc_last = desc;
+00700                 desc++;
+00701         }
+00702 
+00703         /* Set the last, ioc and sp bits on the Last DMA Descriptor */
+00704         desc_last->status.b.l = 1;
+00705         desc_last->status.b.ioc = 1;
+00706         desc_last->status.b.sp = ep->dwc_ep.sent_zlp;
+00707         cfiep->dma_desc_last = desc_last;
+00708         cfiep->desc_count = concatval->hdr.bDescCount;
+00709 }
+00710 
+00714 static void cfi_build_circ_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
+00715                                  dwc_otg_pcd_request_t * req)
+00716 {
+00717         /* @todo: MAS - add implementation when this feature needs to be tested */
+00718 }
+00719 
+00723 static void cfi_build_align_descs(struct cfiobject *cfi, cfi_ep_t * cfiep,
+00724                                   dwc_otg_pcd_request_t * req)
+00725 {
+00726         struct dwc_otg_pcd_ep *ep = cfiep->ep;
+00727         ddma_align_buffer_setup_t *alignval = cfiep->bm_align;
+00728         struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs;
+00729         dma_addr_t buff_addr = req->dma;
+00730 
+00731         desc->status.b.bs = BS_HOST_BUSY;
+00732         desc->status.b.l = 1;
+00733         desc->status.b.ioc = 1;
+00734         desc->status.b.sp = ep->dwc_ep.sent_zlp;
+00735         desc->status.b.bytes = req->length;
+00736         /* Adjust the buffer alignment */
+00737         desc->buf = (buff_addr + alignval->bAlign);
+00738         desc->status.b.bs = BS_HOST_READY;
+00739         cfiep->dma_desc_last = desc;
+00740         cfiep->desc_count = 1;
+00741 }
+00742 
+00747 static void cfi_build_descriptors(struct cfiobject *cfi,
+00748                                   struct dwc_otg_pcd *pcd,
+00749                                   struct dwc_otg_pcd_ep *ep,
+00750                                   dwc_otg_pcd_request_t * req)
+00751 {
+00752         cfi_ep_t *cfiep;
+00753 
+00754         /* Get the cfiep by the dwc_otg_pcd_ep */
+00755         cfiep = get_cfi_ep_by_pcd_ep(cfi, ep);
+00756         if (NULL == cfiep) {
+00757                 CFI_INFO("%s: Unable to find a matching active endpoint\n",
+00758                          __func__);
+00759                 return;
+00760         }
+00761 
+00762         cfiep->xfer_len = req->length;
+00763 
+00764         /* Iterate through all the DMA descriptors */
+00765         switch (cfiep->ep->dwc_ep.buff_mode) {
+00766         case BM_SG:
+00767                 cfi_build_sg_descs(cfi, cfiep, req);
+00768                 break;
+00769 
+00770         case BM_CONCAT:
+00771                 cfi_build_concat_descs(cfi, cfiep, req);
+00772                 break;
+00773 
+00774         case BM_CIRCULAR:
+00775                 cfi_build_circ_descs(cfi, cfiep, req);
+00776                 break;
+00777 
+00778         case BM_ALIGN:
+00779                 cfi_build_align_descs(cfi, cfiep, req);
+00780                 break;
+00781 
+00782         default:
+00783                 break;
+00784         }
+00785 }
+00786 
+00790 static void *cfi_ep_alloc_buf(struct cfiobject *cfi, struct dwc_otg_pcd *pcd,
+00791                               struct dwc_otg_pcd_ep *ep, dma_addr_t * dma,
+00792                               unsigned size, gfp_t flags)
+00793 {
+00794         return dwc_dma_alloc(size, dma);
+00795 }
+00796 
+00800 int init_cfi(cfiobject_t * cfiobj)
+00801 {
+00802         CFI_INFO("%s\n", __func__);
+00803 
+00804         /* Allocate a buffer for IN XFERs */
+00805         cfiobj->buf_in.buf =
+00806             dwc_dma_alloc(CFI_IN_BUF_LEN, &cfiobj->buf_in.addr);
+00807         if (NULL == cfiobj->buf_in.buf) {
+00808                 CFI_INFO("Unable to allocate buffer for INs\n");
+00809                 return -DWC_E_NO_MEMORY;
+00810         }
+00811 
+00812         /* Allocate a buffer for OUT XFERs */
+00813         cfiobj->buf_out.buf =
+00814             dwc_dma_alloc(CFI_OUT_BUF_LEN, &cfiobj->buf_out.addr);
+00815         if (NULL == cfiobj->buf_out.buf) {
+00816                 CFI_INFO("Unable to allocate buffer for OUT\n");
+00817                 return -DWC_E_NO_MEMORY;
+00818         }
+00819 
+00820         /* Initialize the callback function pointers */
+00821         cfiobj->ops.release = cfi_release;
+00822         cfiobj->ops.ep_enable = cfi_ep_enable;
+00823         cfiobj->ops.ctrl_write_complete = cfi_ctrl_write_complete;
+00824         cfiobj->ops.build_descriptors = cfi_build_descriptors;
+00825         cfiobj->ops.ep_alloc_buf = cfi_ep_alloc_buf;
+00826 
+00827         /* Initialize the list of active endpoints in the CFI object */
+00828         DWC_LIST_INIT(&cfiobj->active_eps);
+00829 
+00830         return 0;
+00831 }
+00832 
+00838 static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen,
+00839                                  struct dwc_otg_pcd *pcd,
+00840                                  struct cfi_usb_ctrlrequest *ctrl_req)
+00841 {
+00842         int retval = -DWC_E_NOT_SUPPORTED;
+00843         struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd);
+00844         uint16_t dfifo, rxfifo, txfifo;
+00845 
+00846         switch (ctrl_req->wIndex) {
+00847                 /* Whether the DDMA is enabled or not */
+00848         case FT_ID_DMA_MODE:
+00849                 *buf = (coreif->dma_enable && coreif->dma_desc_enable) ? 1 : 0;
+00850                 retval = 1;
+00851                 break;
+00852 
+00853         case FT_ID_DMA_BUFFER_SETUP:
+00854                 retval = cfi_ep_get_sg_val(buf, pcd, ctrl_req);
+00855                 break;
+00856 
+00857         case FT_ID_DMA_BUFF_ALIGN:
+00858                 retval = cfi_ep_get_align_val(buf, pcd, ctrl_req);
+00859                 break;
+00860 
+00861         case FT_ID_DMA_CONCAT_SETUP:
+00862                 retval = cfi_ep_get_concat_val(buf, pcd, ctrl_req);
+00863                 break;
+00864 
+00865         case FT_ID_DMA_CIRCULAR:
+00866                 CFI_INFO("GetFeature value (FT_ID_DMA_CIRCULAR)\n");
+00867                 break;
+00868 
+00869         case FT_ID_THRESHOLD_SETUP:
+00870                 CFI_INFO("GetFeature value (FT_ID_THRESHOLD_SETUP)\n");
+00871                 break;
+00872 
+00873         case FT_ID_DFIFO_DEPTH:
+00874                 dfifo = get_dfifo_size(coreif);
+00875                 *((uint16_t *) buf) = dfifo;
+00876                 retval = sizeof(uint16_t);
+00877                 break;
+00878 
+00879         case FT_ID_TX_FIFO_DEPTH:
+00880                 retval = get_txfifo_size(pcd, ctrl_req->wValue);
+00881                 if (retval >= 0) {
+00882                         txfifo = retval;
+00883                         *((uint16_t *) buf) = txfifo;
+00884                         retval = sizeof(uint16_t);
+00885                 }
+00886                 break;
+00887 
+00888         case FT_ID_RX_FIFO_DEPTH:
+00889                 retval = get_rxfifo_size(coreif, ctrl_req->wValue);
+00890                 if (retval >= 0) {
+00891                         rxfifo = retval;
+00892                         *((uint16_t *) buf) = rxfifo;
+00893                         retval = sizeof(uint16_t);
+00894                 }
+00895                 break;
+00896         }
+00897 
+00898         return retval;
+00899 }
+00900 
+00904 static int cfi_reset_sg_val(cfi_ep_t * cfiep)
+00905 {
+00906         dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
+00907         return 0;
+00908 }
+00909 
+00913 static int cfi_reset_align_val(cfi_ep_t * cfiep)
+00914 {
+00915         dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t));
+00916         return 0;
+00917 }
+00918 
+00924 static int cfi_reset_concat_val(cfi_ep_t * cfiep)
+00925 {
+00926         /* First we need to free the wTxBytes field */
+00927         if (cfiep->bm_concat->wTxBytes) {
+00928                 dwc_free(cfiep->bm_concat->wTxBytes);
+00929                 cfiep->bm_concat->wTxBytes = NULL;
+00930         }
+00931 
+00932         dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t));
+00933         return 0;
+00934 }
+00935 
+00939 static int cfi_ep_reset_all_setup_vals(cfi_ep_t * cfiep)
+00940 {
+00941         cfi_reset_sg_val(cfiep);
+00942         cfi_reset_align_val(cfiep);
+00943         cfi_reset_concat_val(cfiep);
+00944         return 0;
+00945 }
+00946 
+00947 static int cfi_handle_reset_fifo_val(struct dwc_otg_pcd *pcd, uint8_t ep_addr,
+00948                                      uint8_t rx_rst, uint8_t tx_rst)
+00949 {
+00950         int retval = -DWC_E_INVALID;
+00951         uint16_t tx_siz[15];
+00952         uint16_t rx_siz = 0;
+00953         dwc_otg_pcd_ep_t *ep = NULL;
+00954         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+00955         dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
+00956 
+00957         if (rx_rst) {
+00958                 rx_siz = params->dev_rx_fifo_size;
+00959                 params->dev_rx_fifo_size = GET_CORE_IF(pcd)->init_rxfsiz;
+00960         }
+00961 
+00962         if (tx_rst) {
+00963                 if (ep_addr == 0) {
+00964                         int i;
+00965 
+00966                         for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
+00967                                 tx_siz[i] =
+00968                                     core_if->core_params->dev_tx_fifo_size[i];
+00969                                 core_if->core_params->dev_tx_fifo_size[i] =
+00970                                     core_if->init_txfsiz[i];
+00971                         }
+00972                 } else {
+00973 
+00974                         ep = get_ep_by_addr(pcd, ep_addr);
+00975 
+00976                         if (NULL == ep) {
+00977                                 CFI_INFO
+00978                                     ("%s: Unable to get the endpoint addr=0x%02x\n",
+00979                                      __func__, ep_addr);
+00980                                 return -DWC_E_INVALID;
+00981                         }
+00982 
+00983                         tx_siz[0] =
+00984                             params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num -
+00985                                                      1];
+00986                         params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] =
+00987                             GET_CORE_IF(pcd)->init_txfsiz[ep->dwc_ep.
+00988                                                           tx_fifo_num - 1];
+00989                 }
+00990         }
+00991 
+00992         if (resize_fifos(GET_CORE_IF(pcd))) {
+00993                 retval = 0;
+00994         } else {
+00995                 CFI_INFO
+00996                     ("%s: Error resetting the feature Reset All(FIFO size)\n",
+00997                      __func__);
+00998                 if (rx_rst) {
+00999                         params->dev_rx_fifo_size = rx_siz;
+01000                 }
+01001 
+01002                 if (tx_rst) {
+01003                         if (ep_addr == 0) {
+01004                                 int i;
+01005                                 for (i = 0; i < core_if->hwcfg4.b.num_in_eps;
+01006                                      i++) {
+01007                                         core_if->core_params->
+01008                                             dev_tx_fifo_size[i] = tx_siz[i];
+01009                                 }
+01010                         } else {
+01011                                 params->dev_tx_fifo_size[ep->dwc_ep.
+01012                                                          tx_fifo_num - 1] =
+01013                                     tx_siz[0];
+01014                         }
+01015                 }
+01016                 retval = -DWC_E_INVALID;
+01017         }
+01018         return retval;
+01019 }
+01020 
+01021 static int cfi_handle_reset_all(struct dwc_otg_pcd *pcd, uint8_t addr)
+01022 {
+01023         int retval = 0;
+01024         cfi_ep_t *cfiep;
+01025         cfiobject_t *cfi = pcd->cfi;
+01026         dwc_list_link_t *tmp;
+01027 
+01028         retval = cfi_handle_reset_fifo_val(pcd, addr, 1, 1);
+01029         if (retval < 0) {
+01030                 return retval;
+01031         }
+01032 
+01033         /* If the EP address is known then reset the features for only that EP */
+01034         if (addr) {
+01035                 cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
+01036                 if (NULL == cfiep) {
+01037                         CFI_INFO("%s: Error getting the EP address 0x%02x\n",
+01038                                  __func__, addr);
+01039                         return -DWC_E_INVALID;
+01040                 }
+01041                 retval = cfi_ep_reset_all_setup_vals(cfiep);
+01042                 cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
+01043         }
+01044         /* Otherwise (wValue == 0), reset all features of all EP's */
+01045         else {
+01046                 /* Traverse all the active EP's and reset the feature(s) value(s) */
+01047                 //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
+01048                 DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
+01049                         cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
+01050                         retval = cfi_ep_reset_all_setup_vals(cfiep);
+01051                         cfiep->ep->dwc_ep.buff_mode = BM_STANDARD;
+01052                         if (retval < 0) {
+01053                                 CFI_INFO
+01054                                     ("%s: Error resetting the feature Reset All\n",
+01055                                      __func__);
+01056                                 return retval;
+01057                         }
+01058                 }
+01059         }
+01060         return retval;
+01061 }
+01062 
+01063 static int cfi_handle_reset_dma_buff_setup(struct dwc_otg_pcd *pcd,
+01064                                            uint8_t addr)
+01065 {
+01066         int retval = 0;
+01067         cfi_ep_t *cfiep;
+01068         cfiobject_t *cfi = pcd->cfi;
+01069         dwc_list_link_t *tmp;
+01070 
+01071         /* If the EP address is known then reset the features for only that EP */
+01072         if (addr) {
+01073                 cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
+01074                 if (NULL == cfiep) {
+01075                         CFI_INFO("%s: Error getting the EP address 0x%02x\n",
+01076                                  __func__, addr);
+01077                         return -DWC_E_INVALID;
+01078                 }
+01079                 retval = cfi_reset_sg_val(cfiep);
+01080         }
+01081         /* Otherwise (wValue == 0), reset all features of all EP's */
+01082         else {
+01083                 /* Traverse all the active EP's and reset the feature(s) value(s) */
+01084                 //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
+01085                 DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
+01086                         cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
+01087                         retval = cfi_reset_sg_val(cfiep);
+01088                         if (retval < 0) {
+01089                                 CFI_INFO
+01090                                     ("%s: Error resetting the feature Buffer Setup\n",
+01091                                      __func__);
+01092                                 return retval;
+01093                         }
+01094                 }
+01095         }
+01096         return retval;
+01097 }
+01098 
+01099 static int cfi_handle_reset_concat_val(struct dwc_otg_pcd *pcd, uint8_t addr)
+01100 {
+01101         int retval = 0;
+01102         cfi_ep_t *cfiep;
+01103         cfiobject_t *cfi = pcd->cfi;
+01104         dwc_list_link_t *tmp;
+01105 
+01106         /* If the EP address is known then reset the features for only that EP */
+01107         if (addr) {
+01108                 cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
+01109                 if (NULL == cfiep) {
+01110                         CFI_INFO("%s: Error getting the EP address 0x%02x\n",
+01111                                  __func__, addr);
+01112                         return -DWC_E_INVALID;
+01113                 }
+01114                 retval = cfi_reset_concat_val(cfiep);
+01115         }
+01116         /* Otherwise (wValue == 0), reset all features of all EP's */
+01117         else {
+01118                 /* Traverse all the active EP's and reset the feature(s) value(s) */
+01119                 //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
+01120                 DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
+01121                         cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
+01122                         retval = cfi_reset_concat_val(cfiep);
+01123                         if (retval < 0) {
+01124                                 CFI_INFO
+01125                                     ("%s: Error resetting the feature Concatenation Value\n",
+01126                                      __func__);
+01127                                 return retval;
+01128                         }
+01129                 }
+01130         }
+01131         return retval;
+01132 }
+01133 
+01134 static int cfi_handle_reset_align_val(struct dwc_otg_pcd *pcd, uint8_t addr)
+01135 {
+01136         int retval = 0;
+01137         cfi_ep_t *cfiep;
+01138         cfiobject_t *cfi = pcd->cfi;
+01139         dwc_list_link_t *tmp;
+01140 
+01141         /* If the EP address is known then reset the features for only that EP */
+01142         if (addr) {
+01143                 cfiep = get_cfi_ep_by_addr(pcd->cfi, addr);
+01144                 if (NULL == cfiep) {
+01145                         CFI_INFO("%s: Error getting the EP address 0x%02x\n",
+01146                                  __func__, addr);
+01147                         return -DWC_E_INVALID;
+01148                 }
+01149                 retval = cfi_reset_align_val(cfiep);
+01150         }
+01151         /* Otherwise (wValue == 0), reset all features of all EP's */
+01152         else {
+01153                 /* Traverse all the active EP's and reset the feature(s) value(s) */
+01154                 //list_for_each_entry(cfiep, &cfi->active_eps, lh) {
+01155                 DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
+01156                         cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
+01157                         retval = cfi_reset_align_val(cfiep);
+01158                         if (retval < 0) {
+01159                                 CFI_INFO
+01160                                     ("%s: Error resetting the feature Aliignment Value\n",
+01161                                      __func__);
+01162                                 return retval;
+01163                         }
+01164                 }
+01165         }
+01166         return retval;
+01167 
+01168 }
+01169 
+01170 static int cfi_preproc_reset(struct dwc_otg_pcd *pcd,
+01171                              struct cfi_usb_ctrlrequest *req)
+01172 {
+01173         int retval = 0;
+01174 
+01175         switch (req->wIndex) {
+01176         case 0:
+01177                 /* Reset all features */
+01178                 retval = cfi_handle_reset_all(pcd, req->wValue & 0xff);
+01179                 break;
+01180 
+01181         case FT_ID_DMA_BUFFER_SETUP:
+01182                 /* Reset the SG buffer setup */
+01183                 retval =
+01184                     cfi_handle_reset_dma_buff_setup(pcd, req->wValue & 0xff);
+01185                 break;
+01186 
+01187         case FT_ID_DMA_CONCAT_SETUP:
+01188                 /* Reset the Concatenation buffer setup */
+01189                 retval = cfi_handle_reset_concat_val(pcd, req->wValue & 0xff);
+01190                 break;
+01191 
+01192         case FT_ID_DMA_BUFF_ALIGN:
+01193                 /* Reset the Alignment buffer setup */
+01194                 retval = cfi_handle_reset_align_val(pcd, req->wValue & 0xff);
+01195                 break;
+01196 
+01197         case FT_ID_TX_FIFO_DEPTH:
+01198                 retval =
+01199                     cfi_handle_reset_fifo_val(pcd, req->wValue & 0xff, 0, 1);
+01200                 pcd->cfi->need_gadget_att = 0;
+01201                 break;
+01202 
+01203         case FT_ID_RX_FIFO_DEPTH:
+01204                 retval = cfi_handle_reset_fifo_val(pcd, 0, 1, 0);
+01205                 pcd->cfi->need_gadget_att = 0;
+01206                 break;
+01207         default:
+01208                 break;
+01209         }
+01210         return retval;
+01211 }
+01212 
+01216 static int cfi_ep_set_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
+01217 {
+01218         uint8_t inaddr, outaddr;
+01219         cfi_ep_t *epin, *epout;
+01220         ddma_sg_buffer_setup_t *psgval;
+01221         uint32_t desccount, size;
+01222 
+01223         CFI_INFO("%s\n", __func__);
+01224 
+01225         psgval = (ddma_sg_buffer_setup_t *) buf;
+01226         desccount = (uint32_t) psgval->bCount;
+01227         size = (uint32_t) psgval->wSize;
+01228 
+01229         /* Check the DMA descriptor count */
+01230         if ((desccount > MAX_DMA_DESCS_PER_EP) || (desccount == 0)) {
+01231                 CFI_INFO
+01232                     ("%s: The count of DMA Descriptors should be between 1 and %d\n",
+01233                      __func__, MAX_DMA_DESCS_PER_EP);
+01234                 return -DWC_E_INVALID;
+01235         }
+01236 
+01237         /* Check the DMA descriptor count */
+01238 
+01239         if (size == 0) {
+01240 
+01241                 CFI_INFO("%s: The transfer size should be at least 1 byte\n",
+01242                          __func__);
+01243 
+01244                 return -DWC_E_INVALID;
+01245 
+01246         }
+01247 
+01248         inaddr = psgval->bInEndpointAddress;
+01249         outaddr = psgval->bOutEndpointAddress;
+01250 
+01251         epin = get_cfi_ep_by_addr(pcd->cfi, inaddr);
+01252         epout = get_cfi_ep_by_addr(pcd->cfi, outaddr);
+01253 
+01254         if (NULL == epin || NULL == epout) {
+01255                 CFI_INFO
+01256                     ("%s: Unable to get the endpoints inaddr=0x%02x outaddr=0x%02x\n",
+01257                      __func__, inaddr, outaddr);
+01258                 return -DWC_E_INVALID;
+01259         }
+01260 
+01261         epin->ep->dwc_ep.buff_mode = BM_SG;
+01262         dwc_memcpy(epin->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
+01263 
+01264         epout->ep->dwc_ep.buff_mode = BM_SG;
+01265         dwc_memcpy(epout->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t));
+01266 
+01267         return 0;
+01268 }
+01269 
+01273 static int cfi_ep_set_alignment_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
+01274 {
+01275         cfi_ep_t *ep;
+01276         uint8_t addr;
+01277         ddma_align_buffer_setup_t *palignval;
+01278 
+01279         palignval = (ddma_align_buffer_setup_t *) buf;
+01280         addr = palignval->bEndpointAddress;
+01281 
+01282         ep = get_cfi_ep_by_addr(pcd->cfi, addr);
+01283 
+01284         if (NULL == ep) {
+01285                 CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
+01286                          __func__, addr);
+01287                 return -DWC_E_INVALID;
+01288         }
+01289 
+01290         ep->ep->dwc_ep.buff_mode = BM_ALIGN;
+01291         dwc_memcpy(ep->bm_align, palignval, sizeof(ddma_align_buffer_setup_t));
+01292 
+01293         return 0;
+01294 }
+01295 
+01299 static int cfi_ep_set_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd)
+01300 {
+01301         uint8_t addr;
+01302         cfi_ep_t *ep;
+01303         struct _ddma_concat_buffer_setup_hdr *pConcatValHdr;
+01304         uint16_t *pVals;
+01305         uint32_t desccount;
+01306         int i;
+01307         uint16_t mps;
+01308 
+01309         pConcatValHdr = (struct _ddma_concat_buffer_setup_hdr *)buf;
+01310         desccount = (uint32_t) pConcatValHdr->bDescCount;
+01311         pVals = (uint16_t *) (buf + BS_CONCAT_VAL_HDR_LEN);
+01312 
+01313         /* Check the DMA descriptor count */
+01314         if (desccount > MAX_DMA_DESCS_PER_EP) {
+01315                 CFI_INFO("%s: Maximum DMA Descriptor count should be %d\n",
+01316                          __func__, MAX_DMA_DESCS_PER_EP);
+01317                 return -DWC_E_INVALID;
+01318         }
+01319 
+01320         addr = pConcatValHdr->bEndpointAddress;
+01321         ep = get_cfi_ep_by_addr(pcd->cfi, addr);
+01322         if (NULL == ep) {
+01323                 CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
+01324                          __func__, addr);
+01325                 return -DWC_E_INVALID;
+01326         }
+01327 
+01328         mps = UGETW(ep->ep->desc->wMaxPacketSize);
+01329 
+01330 #if 0
+01331         for (i = 0; i < desccount; i++) {
+01332                 CFI_INFO("%s: wTxSize[%d]=0x%04x\n", __func__, i, pVals[i]);
+01333         }
+01334         CFI_INFO("%s: epname=%s; mps=%d\n", __func__, ep->ep->ep.name, mps);
+01335 #endif
+01336 
+01337         /* Check the wTxSizes to be less than or equal to the mps */
+01338         for (i = 0; i < desccount; i++) {
+01339                 if (pVals[i] > mps) {
+01340                         CFI_INFO
+01341                             ("%s: ERROR - the wTxSize[%d] should be <= MPS (wTxSize=%d)\n",
+01342                              __func__, i, pVals[i]);
+01343                         return -DWC_E_INVALID;
+01344                 }
+01345         }
+01346 
+01347         ep->ep->dwc_ep.buff_mode = BM_CONCAT;
+01348         dwc_memcpy(ep->bm_concat, pConcatValHdr, BS_CONCAT_VAL_HDR_LEN);
+01349 
+01350         /* Free the previously allocated storage for the wTxBytes */
+01351         if (ep->bm_concat->wTxBytes) {
+01352                 dwc_free(ep->bm_concat->wTxBytes);
+01353         }
+01354 
+01355         /* Allocate a new storage for the wTxBytes field */
+01356         ep->bm_concat->wTxBytes =
+01357             dwc_alloc(sizeof(uint16_t) * pConcatValHdr->bDescCount);
+01358         if (NULL == ep->bm_concat->wTxBytes) {
+01359                 CFI_INFO("%s: Unable to allocate memory\n", __func__);
+01360                 return -DWC_E_NO_MEMORY;
+01361         }
+01362 
+01363         /* Copy the new values into the wTxBytes filed */
+01364         dwc_memcpy(ep->bm_concat->wTxBytes, buf + BS_CONCAT_VAL_HDR_LEN,
+01365                    sizeof(uint16_t) * pConcatValHdr->bDescCount);
+01366 
+01367         return 0;
+01368 }
+01369 
+01378 static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if)
+01379 {
+01380         dwc_otg_core_params_t *params = core_if->core_params;
+01381         uint16_t dfifo_total = 0;
+01382         int i;
+01383 
+01384         /* The shared RxFIFO size */
+01385         dfifo_total =
+01386             params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
+01387 
+01388         /* Add up each TxFIFO size to the total */
+01389         for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
+01390                 dfifo_total += params->dev_tx_fifo_size[i];
+01391         }
+01392 
+01393         return dfifo_total;
+01394 }
+01395 
+01404 static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue)
+01405 {
+01406         switch (wValue >> 8) {
+01407         case 0:
+01408                 return (core_if->pwron_rxfsiz <
+01409                         32768) ? core_if->pwron_rxfsiz : 32768;
+01410                 break;
+01411         case 1:
+01412                 return core_if->core_params->dev_rx_fifo_size;
+01413                 break;
+01414         default:
+01415                 return -DWC_E_INVALID;
+01416                 break;
+01417         }
+01418 }
+01419 
+01428 static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue)
+01429 {
+01430         dwc_otg_pcd_ep_t *ep;
+01431 
+01432         ep = get_ep_by_addr(pcd, wValue & 0xff);
+01433 
+01434         if (NULL == ep) {
+01435                 CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
+01436                          __func__, wValue & 0xff);
+01437                 return -DWC_E_INVALID;
+01438         }
+01439 
+01440         if (!ep->dwc_ep.is_in) {
+01441                 CFI_INFO
+01442                     ("%s: No Tx FIFO assingned to the Out endpoint addr=0x%02x\n",
+01443                      __func__, wValue & 0xff);
+01444                 return -DWC_E_INVALID;
+01445         }
+01446 
+01447         switch (wValue >> 8) {
+01448         case 0:
+01449                 return (GET_CORE_IF(pcd)->
+01450                         pwron_txfsiz[ep->dwc_ep.tx_fifo_num - 1] <
+01451                         768) ? GET_CORE_IF(pcd)->pwron_txfsiz[ep->dwc_ep.
+01452                                                               tx_fifo_num -
+01453                                                               1] : 32768;
+01454                 break;
+01455         case 1:
+01456                 return GET_CORE_IF(pcd)->core_params->dev_tx_fifo_size[ep->
+01457                                                                        dwc_ep.
+01458                                                                        num - 1];
+01459                 break;
+01460         default:
+01461                 return -DWC_E_INVALID;
+01462                 break;
+01463         }
+01464 }
+01465 
+01475 static uint8_t check_fifo_sizes(dwc_otg_core_if_t * core_if)
+01476 {
+01477         uint16_t dfifo_actual = 0;
+01478         dwc_otg_core_params_t *params = core_if->core_params;
+01479         uint16_t start_addr = 0;
+01480         int i;
+01481 
+01482         dfifo_actual =
+01483             params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size;
+01484 
+01485         for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
+01486                 dfifo_actual += params->dev_tx_fifo_size[i];
+01487         }
+01488 
+01489         if (dfifo_actual > core_if->total_fifo_size) {
+01490                 return 0;
+01491         }
+01492 
+01493         if (params->dev_rx_fifo_size > 32768 || params->dev_rx_fifo_size < 16)
+01494                 return 0;
+01495 
+01496         if (params->dev_nperio_tx_fifo_size > 32768
+01497             || params->dev_nperio_tx_fifo_size < 16)
+01498                 return 0;
+01499 
+01500         for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
+01501 
+01502                 if (params->dev_tx_fifo_size[i] > 768
+01503                     || params->dev_tx_fifo_size[i] < 4)
+01504                         return 0;
+01505         }
+01506 
+01507         if (params->dev_rx_fifo_size > core_if->pwron_rxfsiz)
+01508                 return 0;
+01509         start_addr = params->dev_rx_fifo_size;
+01510 
+01511         if (params->dev_nperio_tx_fifo_size > core_if->pwron_gnptxfsiz)
+01512                 return 0;
+01513         start_addr += params->dev_nperio_tx_fifo_size;
+01514 
+01515         for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
+01516 
+01517                 if (params->dev_tx_fifo_size[i] > core_if->pwron_txfsiz[i])
+01518                         return 0;
+01519                 start_addr += params->dev_tx_fifo_size[i];
+01520         }
+01521 
+01522         return 1;
+01523 }
+01524 
+01533 static uint8_t resize_fifos(dwc_otg_core_if_t * core_if)
+01534 {
+01535         int i = 0;
+01536         dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+01537         dwc_otg_core_params_t *params = core_if->core_params;
+01538         uint32_t rx_fifo_size;
+01539         fifosize_data_t nptxfifosize;
+01540         fifosize_data_t txfifosize[15];
+01541 
+01542         uint32_t rx_fsz_bak;
+01543         uint32_t nptxfsz_bak;
+01544         uint32_t txfsz_bak[15];
+01545 
+01546         uint16_t start_address;
+01547         uint8_t retval = 1;
+01548 
+01549         if (!check_fifo_sizes(core_if)) {
+01550                 return 0;
+01551         }
+01552 
+01553         /* Configure data FIFO sizes */
+01554         if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
+01555                 rx_fsz_bak = dwc_read_reg32(&global_regs->grxfsiz);
+01556                 rx_fifo_size = params->dev_rx_fifo_size;
+01557                 dwc_write_reg32(&global_regs->grxfsiz, rx_fifo_size);
+01558 
+01559                 /*
+01560                  * Tx FIFOs These FIFOs are numbered from 1 to 15.
+01561                  * Indexes of the FIFO size module parameters in the
+01562                  * dev_tx_fifo_size array and the FIFO size registers in
+01563                  * the dptxfsiz_dieptxf array run from 0 to 14.
+01564                  */
+01565 
+01566                 /* Non-periodic Tx FIFO */
+01567                 nptxfsz_bak = dwc_read_reg32(&global_regs->gnptxfsiz);
+01568                 nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
+01569                 start_address = params->dev_rx_fifo_size;
+01570                 nptxfifosize.b.startaddr = start_address;
+01571 
+01572                 dwc_write_reg32(&global_regs->gnptxfsiz, nptxfifosize.d32);
+01573 
+01574                 start_address += nptxfifosize.b.depth;
+01575 
+01576                 for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
+01577                         txfsz_bak[i] =
+01578                             dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i]);
+01579 
+01580                         txfifosize[i].b.depth = params->dev_tx_fifo_size[i];
+01581                         txfifosize[i].b.startaddr = start_address;
+01582                         dwc_write_reg32(&global_regs->dptxfsiz_dieptxf[i],
+01583                                         txfifosize[i].d32);
+01584 
+01585                         start_address += txfifosize[i].b.depth;
+01586                 }
+01587 
+01589                 if (rx_fifo_size != dwc_read_reg32(&global_regs->grxfsiz)) {
+01590                         retval = 0;
+01591                 }
+01592 
+01593                 if (nptxfifosize.d32 != dwc_read_reg32(&global_regs->gnptxfsiz)) {
+01594                         retval = 0;
+01595                 }
+01596 
+01597                 for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
+01598                         if (txfifosize[i].d32 !=
+01599                             dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i])) {
+01600                                 retval = 0;
+01601                         }
+01602                 }
+01603 
+01605                 if (retval == 0) {
+01606                         dwc_write_reg32(&global_regs->grxfsiz, rx_fsz_bak);
+01607 
+01608                         /* Non-periodic Tx FIFO */
+01609                         dwc_write_reg32(&global_regs->gnptxfsiz, nptxfsz_bak);
+01610 
+01611                         for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
+01612                                 dwc_write_reg32(&global_regs->
+01613                                                 dptxfsiz_dieptxf[i],
+01614                                                 txfsz_bak[i]);
+01615                         }
+01616                 }
+01617         } else {
+01618                 return 0;
+01619         }
+01620 
+01621         /* Flush the FIFOs */
+01622         dwc_otg_flush_tx_fifo(core_if, 0x10);   /* all Tx FIFOs */
+01623         dwc_otg_flush_rx_fifo(core_if);
+01624 
+01625         return retval;
+01626 }
+01627 
+01631 static int cfi_ep_set_tx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
+01632 {
+01633         int retval;
+01634         uint32_t fsiz;
+01635         uint16_t size;
+01636         uint16_t ep_addr;
+01637         dwc_otg_pcd_ep_t *ep;
+01638         dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
+01639         tx_fifo_size_setup_t *ptxfifoval;
+01640 
+01641         ptxfifoval = (tx_fifo_size_setup_t *) buf;
+01642         ep_addr = ptxfifoval->bEndpointAddress;
+01643         size = ptxfifoval->wDepth;
+01644 
+01645         ep = get_ep_by_addr(pcd, ep_addr);
+01646 
+01647         CFI_INFO
+01648             ("%s: Set Tx FIFO size: endpoint addr=0x%02x, depth=%d, FIFO Num=%d\n",
+01649              __func__, ep_addr, size, ep->dwc_ep.tx_fifo_num);
+01650 
+01651         if (NULL == ep) {
+01652                 CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n",
+01653                          __func__, ep_addr);
+01654                 return -DWC_E_INVALID;
+01655         }
+01656 
+01657         fsiz = params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1];
+01658         params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = size;
+01659 
+01660         if (resize_fifos(GET_CORE_IF(pcd))) {
+01661                 retval = 0;
+01662         } else {
+01663                 CFI_INFO
+01664                     ("%s: Error setting the feature Tx FIFO Size for EP%d\n",
+01665                      __func__, ep_addr);
+01666                 params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = fsiz;
+01667                 retval = -DWC_E_INVALID;
+01668         }
+01669 
+01670         return retval;
+01671 }
+01672 
+01676 static int cfi_set_rx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd)
+01677 {
+01678         int retval;
+01679         uint32_t fsiz;
+01680         uint16_t size;
+01681         dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params;
+01682         rx_fifo_size_setup_t *prxfifoval;
+01683 
+01684         prxfifoval = (rx_fifo_size_setup_t *) buf;
+01685         size = prxfifoval->wDepth;
+01686 
+01687         fsiz = params->dev_rx_fifo_size;
+01688         params->dev_rx_fifo_size = size;
+01689 
+01690         if (resize_fifos(GET_CORE_IF(pcd))) {
+01691                 retval = 0;
+01692         } else {
+01693                 CFI_INFO("%s: Error setting the feature Rx FIFO Size\n",
+01694                          __func__);
+01695                 params->dev_rx_fifo_size = fsiz;
+01696                 retval = -DWC_E_INVALID;
+01697         }
+01698 
+01699         return retval;
+01700 }
+01701 
+01705 static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
+01706                              struct cfi_usb_ctrlrequest *req)
+01707 {
+01708         int retval = -DWC_E_INVALID;
+01709         uint8_t addr;
+01710         cfi_ep_t *ep;
+01711 
+01712         /* The Low Byte of the wValue contains a non-zero address of the endpoint */
+01713         addr = req->wValue & 0xFF;
+01714         if (addr == 0)          /* The address should be non-zero */
+01715                 return retval;
+01716 
+01717         ep = get_cfi_ep_by_addr(pcd->cfi, addr);
+01718         if (NULL == ep) {
+01719                 CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
+01720                          __func__, addr);
+01721                 return retval;
+01722         }
+01723 
+01724         dwc_memcpy(buf, ep->bm_sg, BS_SG_VAL_DESC_LEN);
+01725         retval = BS_SG_VAL_DESC_LEN;
+01726         return retval;
+01727 }
+01728 
+01733 static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
+01734                                  struct cfi_usb_ctrlrequest *req)
+01735 {
+01736         int retval = -DWC_E_INVALID;
+01737         uint8_t addr;
+01738         cfi_ep_t *ep;
+01739         uint8_t desc_count;
+01740 
+01741         /* The Low Byte of the wValue contains a non-zero address of the endpoint */
+01742         addr = req->wValue & 0xFF;
+01743         if (addr == 0)          /* The address should be non-zero */
+01744                 return retval;
+01745 
+01746         ep = get_cfi_ep_by_addr(pcd->cfi, addr);
+01747         if (NULL == ep) {
+01748                 CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
+01749                          __func__, addr);
+01750                 return retval;
+01751         }
+01752 
+01753         /* Copy the header to the buffer */
+01754         dwc_memcpy(buf, ep->bm_concat, BS_CONCAT_VAL_HDR_LEN);
+01755         /* Advance the buffer pointer by the header size */
+01756         buf += BS_CONCAT_VAL_HDR_LEN;
+01757 
+01758         desc_count = ep->bm_concat->hdr.bDescCount;
+01759         /* Copy alll the wTxBytes to the buffer */
+01760         dwc_memcpy(buf, ep->bm_concat->wTxBytes, sizeof(uid16_t) * desc_count);
+01761 
+01762         retval = BS_CONCAT_VAL_HDR_LEN + sizeof(uid16_t) * desc_count;
+01763         return retval;
+01764 }
+01765 
+01772 static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd,
+01773                                 struct cfi_usb_ctrlrequest *req)
+01774 {
+01775         int retval = -DWC_E_INVALID;
+01776         uint8_t addr;
+01777         cfi_ep_t *ep;
+01778 
+01779         /* The Low Byte of the wValue contains a non-zero address of the endpoint */
+01780         addr = req->wValue & 0xFF;
+01781         if (addr == 0)          /* The address should be non-zero */
+01782                 return retval;
+01783 
+01784         ep = get_cfi_ep_by_addr(pcd->cfi, addr);
+01785         if (NULL == ep) {
+01786                 CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n",
+01787                          __func__, addr);
+01788                 return retval;
+01789         }
+01790 
+01791         dwc_memcpy(buf, ep->bm_align, BS_ALIGN_VAL_HDR_LEN);
+01792         retval = BS_ALIGN_VAL_HDR_LEN;
+01793 
+01794         return retval;
+01795 }
+01796 
+01804 static int cfi_set_feature_value(struct dwc_otg_pcd *pcd)
+01805 {
+01806         int retval = -DWC_E_NOT_SUPPORTED;
+01807         uint16_t wIndex, wValue;
+01808         uint8_t bRequest;
+01809         struct dwc_otg_core_if *coreif;
+01810         cfiobject_t *cfi = pcd->cfi;
+01811         struct cfi_usb_ctrlrequest *ctrl_req;
+01812         uint8_t *buf;
+01813         ctrl_req = &cfi->ctrl_req;
+01814 
+01815         buf = pcd->cfi->ctrl_req.data;
+01816 
+01817         coreif = GET_CORE_IF(pcd);
+01818         bRequest = ctrl_req->bRequest;
+01819         wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex);
+01820         wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue);
+01821 
+01822         /* See which feature is to be modified */
+01823         switch (wIndex) {
+01824         case FT_ID_DMA_BUFFER_SETUP:
+01825                 /* Modify the feature */
+01826                 if ((retval = cfi_ep_set_sg_val(buf, pcd)) < 0)
+01827                         return retval;
+01828 
+01829                 /* And send this request to the gadget */
+01830                 cfi->need_gadget_att = 1;
+01831                 break;
+01832 
+01833         case FT_ID_DMA_BUFF_ALIGN:
+01834                 if ((retval = cfi_ep_set_alignment_val(buf, pcd)) < 0)
+01835                         return retval;
+01836                 cfi->need_gadget_att = 1;
+01837                 break;
+01838 
+01839         case FT_ID_DMA_CONCAT_SETUP:
+01840                 /* Modify the feature */
+01841                 if ((retval = cfi_ep_set_concat_val(buf, pcd)) < 0)
+01842                         return retval;
+01843                 cfi->need_gadget_att = 1;
+01844                 break;
+01845 
+01846         case FT_ID_DMA_CIRCULAR:
+01847                 CFI_INFO("FT_ID_DMA_CIRCULAR\n");
+01848                 break;
+01849 
+01850         case FT_ID_THRESHOLD_SETUP:
+01851                 CFI_INFO("FT_ID_THRESHOLD_SETUP\n");
+01852                 break;
+01853 
+01854         case FT_ID_DFIFO_DEPTH:
+01855                 CFI_INFO("FT_ID_DFIFO_DEPTH\n");
+01856                 break;
+01857 
+01858         case FT_ID_TX_FIFO_DEPTH:
+01859                 CFI_INFO("FT_ID_TX_FIFO_DEPTH\n");
+01860                 if ((retval = cfi_ep_set_tx_fifo_val(buf, pcd)) < 0)
+01861                         return retval;
+01862                 cfi->need_gadget_att = 0;
+01863                 break;
+01864 
+01865         case FT_ID_RX_FIFO_DEPTH:
+01866                 CFI_INFO("FT_ID_RX_FIFO_DEPTH\n");
+01867                 if ((retval = cfi_set_rx_fifo_val(buf, pcd)) < 0)
+01868                         return retval;
+01869                 cfi->need_gadget_att = 0;
+01870                 break;
+01871         }
+01872 
+01873         return retval;
+01874 }
+01875 
+01876 #endif                          //DWC_UTE_CFI
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cfi_8c.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cfi_8c.html new file mode 100644 index 000000000000..44402b4f174b --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cfi_8c.html @@ -0,0 +1,36 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_cfi.c File Reference + + + + + + +

dwc_otg_cfi.c File Reference

This file contains the most of the CFI implementation for the OTG. More... +

+ +

+Go to the source code of this file. + +
+


Detailed Description

+This file contains the most of the CFI implementation for the OTG. +

+ +

+Definition in file dwc_otg_cfi.c.


Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cfi_8h-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cfi_8h-source.html new file mode 100644 index 000000000000..28a9d364006a --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cfi_8h-source.html @@ -0,0 +1,299 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_cfi.h Source File + + + + + + +

dwc_otg_cfi.h

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00003  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00004  * otherwise expressly agreed to in writing between Synopsys and you.
+00005  * 
+00006  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00007  * any End User Software License Agreement or Agreement for Licensed Product
+00008  * with Synopsys or any supplement thereto. You are permitted to use and
+00009  * redistribute this Software in source and binary forms, with or without
+00010  * modification, provided that redistributions of source code must retain this
+00011  * notice. You may not view, use, disclose, copy or distribute this file or
+00012  * any information contained herein except pursuant to this license grant from
+00013  * Synopsys. If you do not agree with this notice, including the disclaimer
+00014  * below, then you are not authorized to use the Software.
+00015  * 
+00016  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00017  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00018  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00019  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00020  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00021  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00022  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00023  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00024  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00025  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00026  * DAMAGE.
+00027  * ========================================================================== */
+00028 
+00029 #if !defined(__DWC_OTG_CFI_H__)
+00030 #define __DWC_OTG_CFI_H__
+00031 
+00032 #include "dwc_otg_pcd.h"
+00033 #include "dwc_cfi_common.h"
+00034 
+00043 struct dwc_otg_pcd;
+00044 struct dwc_otg_pcd_ep;
+00045 
+00048 #define FT_ID_DMA_MODE                                  0x0001
+00049 #define FT_ID_DMA_BUFFER_SETUP                  0x0002
+00050 #define FT_ID_DMA_BUFF_ALIGN                    0x0003
+00051 #define FT_ID_DMA_CONCAT_SETUP                  0x0004
+00052 #define FT_ID_DMA_CIRCULAR                              0x0005
+00053 #define FT_ID_THRESHOLD_SETUP                   0x0006
+00054 #define FT_ID_DFIFO_DEPTH                               0x0007
+00055 #define FT_ID_TX_FIFO_DEPTH                             0x0008
+00056 #define FT_ID_RX_FIFO_DEPTH                             0x0009
+00057 
+00058 /**********************************************************/
+00059 #define CFI_INFO_DEF
+00060 
+00061 #ifdef CFI_INFO_DEF
+00062 #define CFI_INFO(fmt...)        DWC_PRINTF("CFI: " fmt);
+00063 #else
+00064 #define CFI_INFO(fmt...)
+00065 #endif
+00066 
+00067 #define min(x,y) ({ \
+00068         x < y ? x : y; })
+00069 
+00070 #define max(x,y) ({ \
+00071         x > y ? x : y; })
+00072 
+00077 struct _ddma_sg_buffer_setup {
+00078 #define BS_SG_VAL_DESC_LEN      6
+00079         /* The OUT EP address */
+00080         uint8_t bOutEndpointAddress;
+00081         /* The IN EP address */
+00082         uint8_t bInEndpointAddress;
+00083         /* Number of bytes to put between transfer segments (must be DWORD boundaries) */
+00084         uint8_t bOffset;
+00085         /* The number of transfer segments (a DMA descriptors per each segment) */
+00086         uint8_t bCount;
+00087         /* Size (in byte) of each transfer segment */
+00088         uint16_t wSize;
+00089 } __attribute__ ((packed));
+00090 typedef struct _ddma_sg_buffer_setup ddma_sg_buffer_setup_t;
+00091 
+00093 struct _ddma_concat_buffer_setup_hdr {
+00094 #define BS_CONCAT_VAL_HDR_LEN   4
+00095         /* The endpoint for which the buffer is to be set up */
+00096         uint8_t bEndpointAddress;
+00097         /* The count of descriptors to be used */
+00098         uint8_t bDescCount;
+00099         /* The total size of the transfer */
+00100         uint16_t wSize;
+00101 } __attribute__ ((packed));
+00102 typedef struct _ddma_concat_buffer_setup_hdr ddma_concat_buffer_setup_hdr_t;
+00103 
+00105 struct _ddma_concat_buffer_setup {
+00106         /* The SG header */
+00107         ddma_concat_buffer_setup_hdr_t hdr;
+00108 
+00109         /* The XFER sizes pointer (allocated dynamically) */
+00110         uint16_t *wTxBytes;
+00111 } __attribute__ ((packed));
+00112 typedef struct _ddma_concat_buffer_setup ddma_concat_buffer_setup_t;
+00113 
+00115 struct _ddma_align_buffer_setup {
+00116 #define BS_ALIGN_VAL_HDR_LEN    2
+00117         uint8_t bEndpointAddress;
+00118         uint8_t bAlign;
+00119 } __attribute__ ((packed));
+00120 typedef struct _ddma_align_buffer_setup ddma_align_buffer_setup_t;
+00121 
+00123 struct _tx_fifo_size_setup {
+00124         uint8_t bEndpointAddress;
+00125         uint16_t wDepth;
+00126 } __attribute__ ((packed));
+00127 typedef struct _tx_fifo_size_setup tx_fifo_size_setup_t;
+00128 
+00130 struct _rx_fifo_size_setup {
+00131         uint16_t wDepth;
+00132 } __attribute__ ((packed));
+00133 typedef struct _rx_fifo_size_setup rx_fifo_size_setup_t;
+00134 
+00140 struct cfi_usb_ctrlrequest {
+00141         uint8_t bRequestType;
+00142         uint8_t bRequest;
+00143         uint16_t wValue;
+00144         uint16_t wIndex;
+00145         uint16_t wLength;
+00146         uint8_t *data;
+00147 } UPACKED;
+00148 
+00149 /*---------------------------------------------------------------------------*/
+00150 
+00156 struct cfi_ep {
+00157         /* Entry for the list container */
+00158         dwc_list_link_t lh;
+00159         /* Pointer to the active PCD endpoint structure */
+00160         struct dwc_otg_pcd_ep *ep;
+00161         /* The last descriptor in the chain of DMA descriptors of the endpoint */
+00162         struct dwc_otg_dma_desc *dma_desc_last;
+00163         /* The SG feature value */
+00164         ddma_sg_buffer_setup_t *bm_sg;
+00165         /* The Circular feature value */
+00166         ddma_sg_buffer_setup_t *bm_circ;
+00167         /* The Concatenation feature value */
+00168         ddma_concat_buffer_setup_t *bm_concat;
+00169         /* The Alignment feature value */
+00170         ddma_align_buffer_setup_t *bm_align;
+00171         /* XFER length */
+00172         uint32_t xfer_len;
+00173         /* 
+00174          * Count of DMA descriptors currently used.
+00175          * The total should not exceed the MAX_DMA_DESCS_PER_EP value
+00176          * defined in the dwc_otg_cil.h
+00177          */
+00178         uint32_t desc_count;
+00179 };
+00180 typedef struct cfi_ep cfi_ep_t;
+00181 
+00182 typedef struct cfi_dma_buff {
+00183 #define CFI_IN_BUF_LEN  1024
+00184 #define CFI_OUT_BUF_LEN 1024
+00185         dma_addr_t addr;
+00186         uint8_t *buf;
+00187 } cfi_dma_buff_t;
+00188 
+00189 struct cfiobject;
+00190 
+00199 typedef struct cfi_ops {
+00200         int (*ep_enable) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
+00201                           struct dwc_otg_pcd_ep * ep);
+00202         void *(*ep_alloc_buf) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd,
+00203                                struct dwc_otg_pcd_ep * ep, dma_addr_t * dma,
+00204                                unsigned size, gfp_t flags);
+00205         void (*release) (struct cfiobject * cfi);
+00206         int (*ctrl_write_complete) (struct cfiobject * cfi,
+00207                                     struct dwc_otg_pcd * pcd);
+00208         void (*build_descriptors) (struct cfiobject * cfi,
+00209                                    struct dwc_otg_pcd * pcd,
+00210                                    struct dwc_otg_pcd_ep * ep,
+00211                                    dwc_otg_pcd_request_t * req);
+00212 } cfi_ops_t;
+00213 
+00214 struct cfiobject {
+00215         cfi_ops_t ops;
+00216         struct dwc_otg_pcd *pcd;
+00217         struct usb_gadget *gadget;
+00218 
+00219         /* Buffers used to send/receive CFI-related request data */
+00220         cfi_dma_buff_t buf_in;
+00221         cfi_dma_buff_t buf_out;
+00222 
+00223         /* CFI specific Control request wrapper */
+00224         struct cfi_usb_ctrlrequest ctrl_req;
+00225 
+00226         /* The list of active EP's in the PCD of type cfi_ep_t */
+00227         dwc_list_link_t active_eps;
+00228 
+00229         /* This flag shall control the propagation of a specific request
+00230          * to the gadget's processing routines.
+00231          * 0 - no gadget handling
+00232          * 1 - the gadget needs to know about this request (w/o completing a status 
+00233          * phase - just return a 0 to the _setup callback)
+00234          */
+00235         uint8_t need_gadget_att;
+00236 
+00237         /* Flag indicating whether the status IN phase needs to be 
+00238          * completed by the PCD
+00239          */
+00240         uint8_t need_status_in_complete;
+00241 };
+00242 typedef struct cfiobject cfiobject_t;
+00243 
+00244 #define DUMP_MSG
+00245 
+00246 #if defined(DUMP_MSG)
+00247 static inline void dump_msg(const u8 * buf, unsigned int length)
+00248 {
+00249         unsigned int start, num, i;
+00250         char line[52], *p;
+00251 
+00252         if (length >= 512)
+00253                 return;
+00254 
+00255         start = 0;
+00256         while (length > 0) {
+00257                 num = min(length, 16u);
+00258                 p = line;
+00259                 for (i = 0; i < num; ++i) {
+00260                         if (i == 8)
+00261                                 *p++ = ' ';
+00262                         DWC_SPRINTF(p, " %02x", buf[i]);
+00263                         p += 3;
+00264                 }
+00265                 *p = 0;
+00266                 DWC_DEBUG("%6x: %s\n", start, line);
+00267                 buf += num;
+00268                 start += num;
+00269                 length -= num;
+00270         }
+00271 }
+00272 #else
+00273 static inline void dump_msg(const u8 * buf, unsigned int length)
+00274 {
+00275 }
+00276 #endif
+00277 
+00281 static inline struct cfi_ep *get_cfi_ep_by_addr(struct cfiobject *cfi,
+00282                                                 uint8_t addr)
+00283 {
+00284         struct cfi_ep *pcfiep;
+00285         dwc_list_link_t *tmp;
+00286 
+00287         DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
+00288                 pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
+00289 
+00290                 if (pcfiep->ep->desc->bEndpointAddress == addr) {
+00291                         return pcfiep;
+00292                 }
+00293         }
+00294 
+00295         return NULL;
+00296 }
+00297 
+00302 static inline struct cfi_ep *get_cfi_ep_by_pcd_ep(struct cfiobject *cfi,
+00303                                                   struct dwc_otg_pcd_ep *ep)
+00304 {
+00305         struct cfi_ep *pcfiep = NULL;
+00306         dwc_list_link_t *tmp;
+00307 
+00308         DWC_LIST_FOREACH(tmp, &cfi->active_eps) {
+00309                 pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh);
+00310                 if (pcfiep->ep == ep) {
+00311                         return pcfiep;
+00312                 }
+00313         }
+00314         return NULL;
+00315 }
+00316 
+00317 int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl);
+00318 
+00319 #endif                          /* (__DWC_OTG_CFI_H__) */
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cfi_8h.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cfi_8h.html new file mode 100644 index 000000000000..f946f37a148c --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cfi_8h.html @@ -0,0 +1,302 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_cfi.h File Reference + + + + + + +

dwc_otg_cfi.h File Reference

This file contains the CFI related OTG PCD specific common constants, interfaces (functions and macros) and data structures. More... +

+#include "dwc_otg_pcd.h"
+#include "dwc_cfi_common.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Structures

struct  _ddma_sg_buffer_setup
 Descriptor DMA SG Buffer setup structure (SG buffer). More...
struct  _ddma_concat_buffer_setup_hdr
 Descriptor DMA Concatenation Buffer setup structure. More...
struct  _ddma_concat_buffer_setup
 Descriptor DMA Concatenation Buffer setup structure. More...
struct  _ddma_align_buffer_setup
 Descriptor DMA Alignment Buffer setup structure. More...
struct  _tx_fifo_size_setup
 Transmit FIFO Size setup structure. More...
struct  _rx_fifo_size_setup
 Transmit FIFO Size setup structure. More...
struct  cfi_usb_ctrlrequest
 struct cfi_usb_ctrlrequest - the CFI implementation of the struct usb_ctrlrequest This structure encapsulates the standard usb_ctrlrequest and adds a pointer to the data returned in the data stage of a 3-stage Control Write requests. More...
struct  cfi_ep
 The CFI wrapper of the enabled and activated dwc_otg_pcd_ep structures. More...
struct  cfi_dma_buff
struct  cfi_ops
 This is the interface for the CFI operations. More...
struct  cfiobject

Defines

+#define __DWC_OTG_CFI_H__
+#define FT_ID_DMA_MODE   0x0001
 This is a request for all Core Features.
+#define FT_ID_DMA_BUFFER_SETUP   0x0002
+#define FT_ID_DMA_BUFF_ALIGN   0x0003
+#define FT_ID_DMA_CONCAT_SETUP   0x0004
+#define FT_ID_DMA_CIRCULAR   0x0005
+#define FT_ID_THRESHOLD_SETUP   0x0006
+#define FT_ID_DFIFO_DEPTH   0x0007
+#define FT_ID_TX_FIFO_DEPTH   0x0008
+#define FT_ID_RX_FIFO_DEPTH   0x0009
+#define CFI_INFO_DEF
+#define CFI_INFO(fmt...)   DWC_PRINTF("CFI: " fmt);
#define min(x, y)
#define max(x, y)
+#define BS_SG_VAL_DESC_LEN   6
+#define BS_CONCAT_VAL_HDR_LEN   4
+#define BS_ALIGN_VAL_HDR_LEN   2
+#define CFI_IN_BUF_LEN   1024
+#define CFI_OUT_BUF_LEN   1024
+#define DUMP_MSG

Typedefs

+typedef _ddma_sg_buffer_setup ddma_sg_buffer_setup_t
+typedef _ddma_concat_buffer_setup_hdr ddma_concat_buffer_setup_hdr_t
+typedef _ddma_concat_buffer_setup ddma_concat_buffer_setup_t
+typedef _ddma_align_buffer_setup ddma_align_buffer_setup_t
+typedef _tx_fifo_size_setup tx_fifo_size_setup_t
+typedef _rx_fifo_size_setup rx_fifo_size_setup_t
+typedef cfi_ep cfi_ep_t
+typedef cfi_dma_buff cfi_dma_buff_t
typedef cfi_ops cfi_ops_t
 This is the interface for the CFI operations.
+typedef cfiobject cfiobject_t

Functions

+static void dump_msg (const u8 *buf, unsigned int length)
+static struct cfi_epget_cfi_ep_by_addr (struct cfiobject *cfi, uint8_t addr)
 This function returns a pointer to cfi_ep_t object with the addr address.
+static struct cfi_epget_cfi_ep_by_pcd_ep (struct cfiobject *cfi, struct dwc_otg_pcd_ep *ep)
 This function returns a pointer to cfi_ep_t object that matches the dwc_otg_pcd_ep object.
+int cfi_setup (struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl)

Variables

_ddma_sg_buffer_setup packed
 Descriptor DMA SG Buffer setup structure (SG buffer).
+_ddma_concat_buffer_setup_hdr packed
 Descriptor DMA Concatenation Buffer setup structure.
+_ddma_concat_buffer_setup packed
 Descriptor DMA Concatenation Buffer setup structure.
+_ddma_align_buffer_setup packed
 Descriptor DMA Alignment Buffer setup structure.
+_tx_fifo_size_setup packed
 Transmit FIFO Size setup structure.
+_rx_fifo_size_setup packed
 Transmit FIFO Size setup structure.
+cfi_usb_ctrlrequest UPACKED
 struct cfi_usb_ctrlrequest - the CFI implementation of the struct usb_ctrlrequest This structure encapsulates the standard usb_ctrlrequest and adds a pointer to the data returned in the data stage of a 3-stage Control Write requests.
+


Detailed Description

+This file contains the CFI related OTG PCD specific common constants, interfaces (functions and macros) and data structures. +

+ +

+Definition in file dwc_otg_cfi.h.


Define Documentation

+ +
+
+ + + + + + + + + + + + +
#define min (x,
 ) 
+
+
+ +

+Value:

({ \
+        x < y ? x : y; })
+
+

+Definition at line 67 of file dwc_otg_cfi.h. +

+

+ +

+
+ + + + + + + + + + + + +
#define max (x,
 ) 
+
+
+ +

+Value:

({ \
+        x > y ? x : y; })
+
+

+Definition at line 70 of file dwc_otg_cfi.h. +

+

+


Typedef Documentation

+ +
+
+ + + + +
typedef struct cfi_ops cfi_ops_t
+
+
+ +

+This is the interface for the CFI operations. +

+

Parameters:
+ + + + +
ep_enable Called when any endpoint is enabled and activated.
release Called when the CFI object is released and it needs to correctly deallocate the dynamic memory
ctrl_write_complete Called when the data stage of the request is complete
+
+ +
+

+


Variable Documentation

+ +
+
+ + + + +
struct _ddma_sg_buffer_setup packed
+
+
+ +

+Descriptor DMA SG Buffer setup structure (SG buffer). +

+This structure is also used for setting up a buffer for Circular DDMA. +

+

+


Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil_8c-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil_8c-source.html new file mode 100644 index 000000000000..f7684d695faf --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil_8c-source.html @@ -0,0 +1,4922 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_cil.c Source File + + + + + + +

dwc_otg_cil.c

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.c $
+00003  * $Revision: #159 $
+00004  * $Date: 2009/04/21 $
+00005  * $Change: 1237465 $
+00006  *
+00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009  * otherwise expressly agreed to in writing between Synopsys and you.
+00010  * 
+00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012  * any End User Software License Agreement or Agreement for Licensed Product
+00013  * with Synopsys or any supplement thereto. You are permitted to use and
+00014  * redistribute this Software in source and binary forms, with or without
+00015  * modification, provided that redistributions of source code must retain this
+00016  * notice. You may not view, use, disclose, copy or distribute this file or
+00017  * any information contained herein except pursuant to this license grant from
+00018  * Synopsys. If you do not agree with this notice, including the disclaimer
+00019  * below, then you are not authorized to use the Software.
+00020  * 
+00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031  * DAMAGE.
+00032  * ========================================================================== */
+00033 
+00060 #include "dwc_os.h"
+00061 #include "dwc_otg_regs.h"
+00062 #include "dwc_otg_cil.h"
+00063 
+00064 static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if);
+00065 
+00078 dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * reg_base_addr)
+00079 {
+00080         dwc_otg_core_if_t *core_if = 0;
+00081         dwc_otg_dev_if_t *dev_if = 0;
+00082         dwc_otg_host_if_t *host_if = 0;
+00083         uint8_t *reg_base = (uint8_t *) reg_base_addr;
+00084         int i = 0;
+00085 
+00086         DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, reg_base_addr);
+00087 
+00088         core_if = dwc_alloc(sizeof(dwc_otg_core_if_t));
+00089 
+00090         if (core_if == 0) {
+00091                 DWC_DEBUGPL(DBG_CIL,
+00092                             "Allocation of dwc_otg_core_if_t failed\n");
+00093                 return 0;
+00094         }
+00095         core_if->core_global_regs = (dwc_otg_core_global_regs_t *) reg_base;
+00096 
+00097         /*
+00098          * Allocate the Device Mode structures.
+00099          */
+00100         dev_if = dwc_alloc(sizeof(dwc_otg_dev_if_t));
+00101 
+00102         if (dev_if == 0) {
+00103                 DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_dev_if_t failed\n");
+00104                 dwc_free(core_if);
+00105                 return 0;
+00106         }
+00107 
+00108         dev_if->dev_global_regs =
+00109             (dwc_otg_device_global_regs_t *) (reg_base +
+00110                                               DWC_DEV_GLOBAL_REG_OFFSET);
+00111 
+00112         for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+00113                 dev_if->in_ep_regs[i] = (dwc_otg_dev_in_ep_regs_t *)
+00114                     (reg_base + DWC_DEV_IN_EP_REG_OFFSET +
+00115                      (i * DWC_EP_REG_OFFSET));
+00116 
+00117                 dev_if->out_ep_regs[i] = (dwc_otg_dev_out_ep_regs_t *)
+00118                     (reg_base + DWC_DEV_OUT_EP_REG_OFFSET +
+00119                      (i * DWC_EP_REG_OFFSET));
+00120                 DWC_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p\n",
+00121                             i, &dev_if->in_ep_regs[i]->diepctl);
+00122                 DWC_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p\n",
+00123                             i, &dev_if->out_ep_regs[i]->doepctl);
+00124         }
+00125 
+00126         dev_if->speed = 0;      // unknown
+00127 
+00128         core_if->dev_if = dev_if;
+00129 
+00130         /*
+00131          * Allocate the Host Mode structures.
+00132          */
+00133         host_if = dwc_alloc(sizeof(dwc_otg_host_if_t));
+00134 
+00135         if (host_if == 0) {
+00136                 DWC_DEBUGPL(DBG_CIL,
+00137                             "Allocation of dwc_otg_host_if_t failed\n");
+00138                 dwc_free(dev_if);
+00139                 dwc_free(core_if);
+00140                 return 0;
+00141         }
+00142 
+00143         host_if->host_global_regs = (dwc_otg_host_global_regs_t *)
+00144             (reg_base + DWC_OTG_HOST_GLOBAL_REG_OFFSET);
+00145 
+00146         host_if->hprt0 =
+00147             (uint32_t *) (reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET);
+00148 
+00149         for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+00150                 host_if->hc_regs[i] = (dwc_otg_hc_regs_t *)
+00151                     (reg_base + DWC_OTG_HOST_CHAN_REGS_OFFSET +
+00152                      (i * DWC_OTG_CHAN_REGS_OFFSET));
+00153                 DWC_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n",
+00154                             i, &host_if->hc_regs[i]->hcchar);
+00155         }
+00156 
+00157         host_if->num_host_channels = MAX_EPS_CHANNELS;
+00158         core_if->host_if = host_if;
+00159 
+00160         for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+00161                 core_if->data_fifo[i] =
+00162                     (uint32_t *) (reg_base + DWC_OTG_DATA_FIFO_OFFSET +
+00163                                   (i * DWC_OTG_DATA_FIFO_SIZE));
+00164                 DWC_DEBUGPL(DBG_CILV, "data_fifo[%d]=0x%08x\n",
+00165                             i, (unsigned)core_if->data_fifo[i]);
+00166         }
+00167 
+00168         core_if->pcgcctl = (uint32_t *) (reg_base + DWC_OTG_PCGCCTL_OFFSET);
+00169 
+00170         /* Initiate lx_state to L3 disconnected state */
+00171         core_if->lx_state = DWC_OTG_L3;
+00172         /*
+00173          * Store the contents of the hardware configuration registers here for
+00174          * easy access later.
+00175          */
+00176         core_if->hwcfg1.d32 =
+00177             dwc_read_reg32(&core_if->core_global_regs->ghwcfg1);
+00178         core_if->hwcfg2.d32 =
+00179             dwc_read_reg32(&core_if->core_global_regs->ghwcfg2);
+00180         core_if->hwcfg3.d32 =
+00181             dwc_read_reg32(&core_if->core_global_regs->ghwcfg3);
+00182         core_if->hwcfg4.d32 =
+00183             dwc_read_reg32(&core_if->core_global_regs->ghwcfg4);
+00184 
+00185         DWC_DEBUGPL(DBG_CILV, "hwcfg1=%08x\n", core_if->hwcfg1.d32);
+00186         DWC_DEBUGPL(DBG_CILV, "hwcfg2=%08x\n", core_if->hwcfg2.d32);
+00187         DWC_DEBUGPL(DBG_CILV, "hwcfg3=%08x\n", core_if->hwcfg3.d32);
+00188         DWC_DEBUGPL(DBG_CILV, "hwcfg4=%08x\n", core_if->hwcfg4.d32);
+00189 
+00190         core_if->hcfg.d32 =
+00191             dwc_read_reg32(&core_if->host_if->host_global_regs->hcfg);
+00192         core_if->dcfg.d32 =
+00193             dwc_read_reg32(&core_if->dev_if->dev_global_regs->dcfg);
+00194 
+00195         DWC_DEBUGPL(DBG_CILV, "hcfg=%08x\n", core_if->hcfg.d32);
+00196         DWC_DEBUGPL(DBG_CILV, "dcfg=%08x\n", core_if->dcfg.d32);
+00197 
+00198         DWC_DEBUGPL(DBG_CILV, "op_mode=%0x\n", core_if->hwcfg2.b.op_mode);
+00199         DWC_DEBUGPL(DBG_CILV, "arch=%0x\n", core_if->hwcfg2.b.architecture);
+00200         DWC_DEBUGPL(DBG_CILV, "num_dev_ep=%d\n", core_if->hwcfg2.b.num_dev_ep);
+00201         DWC_DEBUGPL(DBG_CILV, "num_host_chan=%d\n",
+00202                     core_if->hwcfg2.b.num_host_chan);
+00203         DWC_DEBUGPL(DBG_CILV, "nonperio_tx_q_depth=0x%0x\n",
+00204                     core_if->hwcfg2.b.nonperio_tx_q_depth);
+00205         DWC_DEBUGPL(DBG_CILV, "host_perio_tx_q_depth=0x%0x\n",
+00206                     core_if->hwcfg2.b.host_perio_tx_q_depth);
+00207         DWC_DEBUGPL(DBG_CILV, "dev_token_q_depth=0x%0x\n",
+00208                     core_if->hwcfg2.b.dev_token_q_depth);
+00209 
+00210         DWC_DEBUGPL(DBG_CILV, "Total FIFO SZ=%d\n",
+00211                     core_if->hwcfg3.b.dfifo_depth);
+00212         DWC_DEBUGPL(DBG_CILV, "xfer_size_cntr_width=%0x\n",
+00213                     core_if->hwcfg3.b.xfer_size_cntr_width);
+00214 
+00215         /*
+00216          * Set the SRP sucess bit for FS-I2c
+00217          */
+00218         core_if->srp_success = 0;
+00219         core_if->srp_timer_started = 0;
+00220 
+00221         /*
+00222          * Create new workqueue and init works
+00223          */
+00224         core_if->wq_otg = DWC_WORKQ_ALLOC("dwc_otg");
+00225         if (core_if->wq_otg == 0) {
+00226                 DWC_WARN("DWC_WORKQ_ALLOC failed\n");
+00227                 dwc_free(host_if);
+00228                 dwc_free(dev_if);
+00229                 dwc_free(core_if);
+00230                 return 0;
+00231         }
+00232 
+00233         core_if->snpsid = dwc_read_reg32(&core_if->core_global_regs->gsnpsid);
+00234 
+00235         DWC_PRINTF("Core Release: %x.%x%x%x\n",
+00236                    (core_if->snpsid >> 12 & 0xF),
+00237                    (core_if->snpsid >> 8 & 0xF),
+00238                    (core_if->snpsid >> 4 & 0xF), (core_if->snpsid & 0xF));
+00239 
+00240         core_if->wkp_timer = DWC_TIMER_ALLOC("Wake Up Timer",
+00241                                              w_wakeup_detected, core_if);
+00242         if (core_if->wkp_timer == 0) {
+00243                 DWC_WARN("DWC_TIMER_ALLOC failed\n");
+00244                 dwc_free(host_if);
+00245                 dwc_free(dev_if);
+00246                 DWC_WORKQ_FREE(core_if->wq_otg);
+00247                 dwc_free(core_if);
+00248                 return 0;
+00249         }
+00250 
+00251         if (dwc_otg_setup_params(core_if)) {
+00252                 DWC_WARN("Error while setting core params\n");
+00253         }
+00254 
+00255         return core_if;
+00256 }
+00257 
+00265 void dwc_otg_cil_remove(dwc_otg_core_if_t * core_if)
+00266 {
+00267         /* Disable all interrupts */
+00268         dwc_modify_reg32(&core_if->core_global_regs->gahbcfg, 1, 0);
+00269         dwc_write_reg32(&core_if->core_global_regs->gintmsk, 0);
+00270 
+00271         if (core_if->wq_otg) {
+00272                 DWC_WORKQ_WAIT_WORK_DONE(core_if->wq_otg, 500);
+00273                 DWC_WORKQ_FREE(core_if->wq_otg);
+00274         }
+00275         if (core_if->dev_if) {
+00276                 dwc_free(core_if->dev_if);
+00277         }
+00278         if (core_if->host_if) {
+00279                 dwc_free(core_if->host_if);
+00280         }
+00281         dwc_free(core_if);
+00282         DWC_TIMER_FREE(core_if->wkp_timer);
+00283         DWC_FREE(core_if->core_params);
+00284 }
+00285 
+00292 void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * core_if)
+00293 {
+00294         gahbcfg_data_t ahbcfg = {.d32 = 0 };
+00295         ahbcfg.b.glblintrmsk = 1;       /* Enable interrupts */
+00296         dwc_modify_reg32(&core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32);
+00297 }
+00298 
+00305 void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * core_if)
+00306 {
+00307         gahbcfg_data_t ahbcfg = {.d32 = 0 };
+00308         ahbcfg.b.glblintrmsk = 1;       /* Enable interrupts */
+00309         dwc_modify_reg32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
+00310 }
+00311 
+00319 static void dwc_otg_enable_common_interrupts(dwc_otg_core_if_t * core_if)
+00320 {
+00321         dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+00322         gintmsk_data_t intr_mask = {.d32 = 0 };
+00323 
+00324         /* Clear any pending OTG Interrupts */
+00325         dwc_write_reg32(&global_regs->gotgint, 0xFFFFFFFF);
+00326 
+00327         /* Clear any pending interrupts */
+00328         dwc_write_reg32(&global_regs->gintsts, 0xFFFFFFFF);
+00329 
+00330         /* 
+00331          * Enable the interrupts in the GINTMSK. 
+00332          */
+00333         intr_mask.b.modemismatch = 1;
+00334         intr_mask.b.otgintr = 1;
+00335 
+00336         if (!core_if->dma_enable) {
+00337                 intr_mask.b.rxstsqlvl = 1;
+00338         }
+00339 
+00340         intr_mask.b.conidstschng = 1;
+00341         intr_mask.b.wkupintr = 1;
+00342         intr_mask.b.disconnect = 1;
+00343         intr_mask.b.usbsuspend = 1;
+00344         intr_mask.b.sessreqintr = 1;
+00345 #ifdef CONFIG_USB_DWC_OTG_LPM
+00346         if (core_if->core_params->lpm_enable) {
+00347                 intr_mask.b.lpmtranrcvd = 1;
+00348         }
+00349 #endif
+00350         dwc_write_reg32(&global_regs->gintmsk, intr_mask.d32);
+00351 }
+00352 
+00357 static void init_fslspclksel(dwc_otg_core_if_t * core_if)
+00358 {
+00359         uint32_t val;
+00360         hcfg_data_t hcfg;
+00361 
+00362         if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
+00363              (core_if->hwcfg2.b.fs_phy_type == 1) &&
+00364              (core_if->core_params->ulpi_fs_ls)) ||
+00365             (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
+00366                 /* Full speed PHY */
+00367                 val = DWC_HCFG_48_MHZ;
+00368         } else {
+00369                 /* High speed PHY running at full speed or high speed */
+00370                 val = DWC_HCFG_30_60_MHZ;
+00371         }
+00372 
+00373         DWC_DEBUGPL(DBG_CIL, "Initializing HCFG.FSLSPClkSel to 0x%1x\n", val);
+00374         hcfg.d32 = dwc_read_reg32(&core_if->host_if->host_global_regs->hcfg);
+00375         hcfg.b.fslspclksel = val;
+00376         dwc_write_reg32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32);
+00377 }
+00378 
+00383 static void init_devspd(dwc_otg_core_if_t * core_if)
+00384 {
+00385         uint32_t val;
+00386         dcfg_data_t dcfg;
+00387 
+00388         if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
+00389              (core_if->hwcfg2.b.fs_phy_type == 1) &&
+00390              (core_if->core_params->ulpi_fs_ls)) ||
+00391             (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
+00392                 /* Full speed PHY */
+00393                 val = 0x3;
+00394         } else if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
+00395                 /* High speed PHY running at full speed */
+00396                 val = 0x1;
+00397         } else {
+00398                 /* High speed PHY running at high speed */
+00399                 val = 0x0;
+00400         }
+00401 
+00402         DWC_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val);
+00403 
+00404         dcfg.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dcfg);
+00405         dcfg.b.devspd = val;
+00406         dwc_write_reg32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
+00407 }
+00408 
+00415 static uint32_t calc_num_in_eps(dwc_otg_core_if_t * core_if)
+00416 {
+00417         uint32_t num_in_eps = 0;
+00418         uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
+00419         uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 3;
+00420         uint32_t num_tx_fifos = core_if->hwcfg4.b.num_in_eps;
+00421         int i;
+00422 
+00423         for (i = 0; i < num_eps; ++i) {
+00424                 if (!(hwcfg1 & 0x1))
+00425                         num_in_eps++;
+00426 
+00427                 hwcfg1 >>= 2;
+00428         }
+00429 
+00430         if (core_if->hwcfg4.b.ded_fifo_en) {
+00431                 num_in_eps =
+00432                     (num_in_eps > num_tx_fifos) ? num_tx_fifos : num_in_eps;
+00433         }
+00434 
+00435         return num_in_eps;
+00436 }
+00437 
+00444 static uint32_t calc_num_out_eps(dwc_otg_core_if_t * core_if)
+00445 {
+00446         uint32_t num_out_eps = 0;
+00447         uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep;
+00448         uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 2;
+00449         int i;
+00450 
+00451         for (i = 0; i < num_eps; ++i) {
+00452                 if (!(hwcfg1 & 0x1))
+00453                         num_out_eps++;
+00454 
+00455                 hwcfg1 >>= 2;
+00456         }
+00457         return num_out_eps;
+00458 }
+00459 
+00467 void dwc_otg_core_init(dwc_otg_core_if_t * core_if)
+00468 {
+00469         int i = 0;
+00470         dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+00471         dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+00472         gahbcfg_data_t ahbcfg = {.d32 = 0 };
+00473         gusbcfg_data_t usbcfg = {.d32 = 0 };
+00474         gi2cctl_data_t i2cctl = {.d32 = 0 };
+00475 
+00476         DWC_DEBUGPL(DBG_CILV, "dwc_otg_core_init(%p)\n", core_if);
+00477 
+00478         /* Common Initialization */
+00479 
+00480         usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
+00481 
+00482         /* Program the ULPI External VBUS bit if needed */
+00483         usbcfg.b.ulpi_ext_vbus_drv =
+00484             (core_if->core_params->phy_ulpi_ext_vbus ==
+00485              DWC_PHY_ULPI_EXTERNAL_VBUS) ? 1 : 0;
+00486 
+00487         /* Set external TS Dline pulsing */
+00488         usbcfg.b.term_sel_dl_pulse =
+00489             (core_if->core_params->ts_dline == 1) ? 1 : 0;
+00490         dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
+00491 
+00492         /* Reset the Controller */
+00493         dwc_otg_core_reset(core_if);
+00494 
+00495         /* Initialize parameters from Hardware configuration registers. */
+00496         dev_if->num_in_eps = calc_num_in_eps(core_if);
+00497         dev_if->num_out_eps = calc_num_out_eps(core_if);
+00498 
+00499         DWC_DEBUGPL(DBG_CIL, "num_dev_perio_in_ep=%d\n",
+00500                     core_if->hwcfg4.b.num_dev_perio_in_ep);
+00501 
+00502         for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
+00503                 dev_if->perio_tx_fifo_size[i] =
+00504                     dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i]) >> 16;
+00505                 DWC_DEBUGPL(DBG_CIL, "Periodic Tx FIFO SZ #%d=0x%0x\n",
+00506                             i, dev_if->perio_tx_fifo_size[i]);
+00507         }
+00508 
+00509         for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
+00510                 dev_if->tx_fifo_size[i] =
+00511                     dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i]) >> 16;
+00512                 DWC_DEBUGPL(DBG_CIL, "Tx FIFO SZ #%d=0x%0x\n",
+00513                             i, dev_if->perio_tx_fifo_size[i]);
+00514         }
+00515 
+00516         core_if->total_fifo_size = core_if->hwcfg3.b.dfifo_depth;
+00517         core_if->rx_fifo_size = dwc_read_reg32(&global_regs->grxfsiz);
+00518         core_if->nperio_tx_fifo_size =
+00519             dwc_read_reg32(&global_regs->gnptxfsiz) >> 16;
+00520 
+00521         DWC_DEBUGPL(DBG_CIL, "Total FIFO SZ=%d\n", core_if->total_fifo_size);
+00522         DWC_DEBUGPL(DBG_CIL, "Rx FIFO SZ=%d\n", core_if->rx_fifo_size);
+00523         DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO SZ=%d\n",
+00524                     core_if->nperio_tx_fifo_size);
+00525 
+00526         /* This programming sequence needs to happen in FS mode before any other
+00527          * programming occurs */
+00528         if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) &&
+00529             (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
+00530                 /* If FS mode with FS PHY */
+00531 
+00532                 /* core_init() is now called on every switch so only call the
+00533                  * following for the first time through. */
+00534                 if (!core_if->phy_init_done) {
+00535                         core_if->phy_init_done = 1;
+00536                         DWC_DEBUGPL(DBG_CIL, "FS_PHY detected\n");
+00537                         usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
+00538                         usbcfg.b.physel = 1;
+00539                         dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
+00540 
+00541                         /* Reset after a PHY select */
+00542                         dwc_otg_core_reset(core_if);
+00543                 }
+00544 
+00545                 /* Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS.      Also
+00546                  * do this on HNP Dev/Host mode switches (done in dev_init and
+00547                  * host_init). */
+00548                 if (dwc_otg_is_host_mode(core_if)) {
+00549                         init_fslspclksel(core_if);
+00550                 } else {
+00551                         init_devspd(core_if);
+00552                 }
+00553 
+00554                 if (core_if->core_params->i2c_enable) {
+00555                         DWC_DEBUGPL(DBG_CIL, "FS_PHY Enabling I2c\n");
+00556                         /* Program GUSBCFG.OtgUtmifsSel to I2C */
+00557                         usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
+00558                         usbcfg.b.otgutmifssel = 1;
+00559                         dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
+00560 
+00561                         /* Program GI2CCTL.I2CEn */
+00562                         i2cctl.d32 = dwc_read_reg32(&global_regs->gi2cctl);
+00563                         i2cctl.b.i2cdevaddr = 1;
+00564                         i2cctl.b.i2cen = 0;
+00565                         dwc_write_reg32(&global_regs->gi2cctl, i2cctl.d32);
+00566                         i2cctl.b.i2cen = 1;
+00567                         dwc_write_reg32(&global_regs->gi2cctl, i2cctl.d32);
+00568                 }
+00569 
+00570         } /* endif speed == DWC_SPEED_PARAM_FULL */
+00571         else {
+00572                 /* High speed PHY. */
+00573                 if (!core_if->phy_init_done) {
+00574                         core_if->phy_init_done = 1;
+00575                         /* HS PHY parameters.  These parameters are preserved
+00576                          * during soft reset so only program the first time.  Do
+00577                          * a soft reset immediately after setting phyif.  */
+00578                         usbcfg.b.ulpi_utmi_sel = core_if->core_params->phy_type;
+00579                         if (usbcfg.b.ulpi_utmi_sel == 1) {
+00580                                 /* ULPI interface */
+00581                                 usbcfg.b.phyif = 0;
+00582                                 usbcfg.b.ddrsel =
+00583                                     core_if->core_params->phy_ulpi_ddr;
+00584                         } else {
+00585                                 /* UTMI+ interface */
+00586                                 if (core_if->core_params->phy_utmi_width == 16) {
+00587                                         usbcfg.b.phyif = 1;
+00588 
+00589                                 } else {
+00590                                         usbcfg.b.phyif = 0;
+00591                                 }
+00592 
+00593                         }
+00594 
+00595                         dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
+00596                         /* Reset after setting the PHY parameters */
+00597                         dwc_otg_core_reset(core_if);
+00598                 }
+00599         }
+00600 
+00601         if ((core_if->hwcfg2.b.hs_phy_type == 2) &&
+00602             (core_if->hwcfg2.b.fs_phy_type == 1) &&
+00603             (core_if->core_params->ulpi_fs_ls)) {
+00604                 DWC_DEBUGPL(DBG_CIL, "Setting ULPI FSLS\n");
+00605                 usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
+00606                 usbcfg.b.ulpi_fsls = 1;
+00607                 usbcfg.b.ulpi_clk_sus_m = 1;
+00608                 dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
+00609         } else {
+00610                 usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
+00611                 usbcfg.b.ulpi_fsls = 0;
+00612                 usbcfg.b.ulpi_clk_sus_m = 0;
+00613                 dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
+00614         }
+00615 
+00616         /* Program the GAHBCFG Register. */
+00617         switch (core_if->hwcfg2.b.architecture) {
+00618 
+00619         case DWC_SLAVE_ONLY_ARCH:
+00620                 DWC_DEBUGPL(DBG_CIL, "Slave Only Mode\n");
+00621                 ahbcfg.b.nptxfemplvl_txfemplvl =
+00622                     DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
+00623                 ahbcfg.b.ptxfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
+00624                 core_if->dma_enable = 0;
+00625                 core_if->dma_desc_enable = 0;
+00626                 break;
+00627 
+00628         case DWC_EXT_DMA_ARCH:
+00629                 DWC_DEBUGPL(DBG_CIL, "External DMA Mode\n");
+00630                 {
+00631                         uint8_t brst_sz = core_if->core_params->dma_burst_size;
+00632                         ahbcfg.b.hburstlen = 0;
+00633                         while (brst_sz > 1) {
+00634                                 ahbcfg.b.hburstlen++;
+00635                                 brst_sz >>= 1;
+00636                         }
+00637                 }
+00638                 core_if->dma_enable = (core_if->core_params->dma_enable != 0);
+00639                 core_if->dma_desc_enable =
+00640                     (core_if->core_params->dma_desc_enable != 0);
+00641                 break;
+00642 
+00643         case DWC_INT_DMA_ARCH:
+00644                 DWC_DEBUGPL(DBG_CIL, "Internal DMA Mode\n");
+00645                 ahbcfg.b.hburstlen = DWC_GAHBCFG_INT_DMA_BURST_INCR;
+00646                 core_if->dma_enable = (core_if->core_params->dma_enable != 0);
+00647                 core_if->dma_desc_enable =
+00648                     (core_if->core_params->dma_desc_enable != 0);
+00649                 break;
+00650 
+00651         }
+00652         if (core_if->dma_enable) {
+00653                 if (core_if->dma_desc_enable) {
+00654                         DWC_PRINTF("Using Descriptor DMA mode\n");
+00655                 } else {
+00656                         DWC_PRINTF("Using Buffer DMA mode\n");
+00657 
+00658                 }
+00659         } else {
+00660                 DWC_PRINTF("Using Slave mode\n");
+00661                 core_if->dma_desc_enable = 0;
+00662         }
+00663         
+00664         ahbcfg.b.dmaenable = core_if->dma_enable;
+00665         dwc_write_reg32(&global_regs->gahbcfg, ahbcfg.d32);
+00666 
+00667         core_if->en_multiple_tx_fifo = core_if->hwcfg4.b.ded_fifo_en;
+00668 
+00669         core_if->pti_enh_enable = core_if->core_params->pti_enable != 0;
+00670         core_if->multiproc_int_enable = core_if->core_params->mpi_enable;
+00671         DWC_PRINTF("Periodic Transfer Interrupt Enhancement - %s\n",
+00672                    ((core_if->pti_enh_enable) ? "enabled" : "disabled"));
+00673         DWC_PRINTF("Multiprocessor Interrupt Enhancement - %s\n",
+00674                    ((core_if->multiproc_int_enable) ? "enabled" : "disabled"));
+00675 
+00676         /* 
+00677          * Program the GUSBCFG register. 
+00678          */
+00679         usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
+00680 
+00681         switch (core_if->hwcfg2.b.op_mode) {
+00682         case DWC_MODE_HNP_SRP_CAPABLE:
+00683                 usbcfg.b.hnpcap = (core_if->core_params->otg_cap ==
+00684                                    DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
+00685                 usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
+00686                                    DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
+00687                 break;
+00688 
+00689         case DWC_MODE_SRP_ONLY_CAPABLE:
+00690                 usbcfg.b.hnpcap = 0;
+00691                 usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
+00692                                    DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
+00693                 break;
+00694 
+00695         case DWC_MODE_NO_HNP_SRP_CAPABLE:
+00696                 usbcfg.b.hnpcap = 0;
+00697                 usbcfg.b.srpcap = 0;
+00698                 break;
+00699 
+00700         case DWC_MODE_SRP_CAPABLE_DEVICE:
+00701                 usbcfg.b.hnpcap = 0;
+00702                 usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
+00703                                    DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
+00704                 break;
+00705 
+00706         case DWC_MODE_NO_SRP_CAPABLE_DEVICE:
+00707                 usbcfg.b.hnpcap = 0;
+00708                 usbcfg.b.srpcap = 0;
+00709                 break;
+00710 
+00711         case DWC_MODE_SRP_CAPABLE_HOST:
+00712                 usbcfg.b.hnpcap = 0;
+00713                 usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
+00714                                    DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
+00715                 break;
+00716 
+00717         case DWC_MODE_NO_SRP_CAPABLE_HOST:
+00718                 usbcfg.b.hnpcap = 0;
+00719                 usbcfg.b.srpcap = 0;
+00720                 break;
+00721         }
+00722 
+00723         dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
+00724 
+00725 #ifdef CONFIG_USB_DWC_OTG_LPM
+00726         if (core_if->core_params->lpm_enable) {
+00727                 glpmcfg_data_t lpmcfg = {.d32 = 0 };
+00728 
+00729                 /* To enable LPM support set lpm_cap_en bit */
+00730                 lpmcfg.b.lpm_cap_en = 1;
+00731 
+00732                 /* Make AppL1Res ACK */
+00733                 lpmcfg.b.appl_resp = 1;
+00734 
+00735                 /* Retry 3 times */
+00736                 lpmcfg.b.retry_count = 3;
+00737 
+00738                 dwc_modify_reg32(&core_if->core_global_regs->glpmcfg,
+00739                                  0, lpmcfg.d32);
+00740 
+00741         }
+00742 #endif
+00743         if (core_if->core_params->ic_usb_cap) {
+00744                 gusbcfg_data_t gusbcfg = {.d32 = 0 };
+00745                 gusbcfg.b.ic_usb_cap = 1;
+00746                 dwc_modify_reg32(&core_if->core_global_regs->gusbcfg,
+00747                                  0, gusbcfg.d32);
+00748         }
+00749 
+00750         /* Enable common interrupts */
+00751         dwc_otg_enable_common_interrupts(core_if);
+00752 
+00753         /* Do device or host intialization based on mode during PCD
+00754          * and HCD initialization  */
+00755         if (dwc_otg_is_host_mode(core_if)) {
+00756                 DWC_DEBUGPL(DBG_ANY, "Host Mode\n");
+00757                 core_if->op_state = A_HOST;
+00758         } else {
+00759                 DWC_DEBUGPL(DBG_ANY, "Device Mode\n");
+00760                 core_if->op_state = B_PERIPHERAL;
+00761 #ifdef DWC_DEVICE_ONLY
+00762                 dwc_otg_core_dev_init(core_if);
+00763 #endif
+00764         }
+00765 }
+00766 
+00772 void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * core_if)
+00773 {
+00774         gintmsk_data_t intr_mask = {.d32 = 0 };
+00775         dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+00776 
+00777         DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__);
+00778 
+00779         /* Disable all interrupts. */
+00780         dwc_write_reg32(&global_regs->gintmsk, 0);
+00781 
+00782         /* Clear any pending interrupts */
+00783         dwc_write_reg32(&global_regs->gintsts, 0xFFFFFFFF);
+00784 
+00785         /* Enable the common interrupts */
+00786         dwc_otg_enable_common_interrupts(core_if);
+00787 
+00788         /* Enable interrupts */
+00789         intr_mask.b.usbreset = 1;
+00790         intr_mask.b.enumdone = 1;
+00791 
+00792         if (!core_if->multiproc_int_enable) {
+00793                 intr_mask.b.inepintr = 1;
+00794                 intr_mask.b.outepintr = 1;
+00795         }
+00796 
+00797         intr_mask.b.erlysuspend = 1;
+00798 
+00799         if (core_if->en_multiple_tx_fifo == 0) {
+00800                 intr_mask.b.epmismatch = 1;
+00801         }
+00802 #ifdef DWC_EN_ISOC
+00803         if (core_if->dma_enable) {
+00804                 if (core_if->dma_desc_enable == 0) {
+00805                         if (core_if->pti_enh_enable) {
+00806                                 dctl_data_t dctl = {.d32 = 0 };
+00807                                 dctl.b.ifrmnum = 1;
+00808                                 dwc_modify_reg32(&core_if->dev_if->
+00809                                                  dev_global_regs->dctl, 0,
+00810                                                  dctl.d32);
+00811                         } else {
+00812                                 intr_mask.b.incomplisoin = 1;
+00813                                 intr_mask.b.incomplisoout = 1;
+00814                         }
+00815                 }
+00816         } else {
+00817                 intr_mask.b.incomplisoin = 1;
+00818                 intr_mask.b.incomplisoout = 1;
+00819         }
+00820 #endif                          /* DWC_EN_ISOC */
+00821 
+00823 #ifdef USE_PERIODIC_EP
+00824         intr_mask.b.isooutdrop = 1;
+00825         intr_mask.b.eopframe = 1;
+00826         intr_mask.b.incomplisoin = 1;
+00827         intr_mask.b.incomplisoout = 1;
+00828 #endif
+00829 
+00830         dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
+00831 
+00832         DWC_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__,
+00833                     dwc_read_reg32(&global_regs->gintmsk));
+00834 }
+00835 
+00843 void dwc_otg_core_dev_init(dwc_otg_core_if_t * core_if)
+00844 {
+00845         int i;
+00846         dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+00847         dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+00848         dwc_otg_core_params_t *params = core_if->core_params;
+00849         dcfg_data_t dcfg = {.d32 = 0 };
+00850         grstctl_t resetctl = {.d32 = 0 };
+00851         uint32_t rx_fifo_size;
+00852         fifosize_data_t nptxfifosize;
+00853         fifosize_data_t txfifosize;
+00854         dthrctl_data_t dthrctl;
+00855         fifosize_data_t ptxfifosize;
+00856 
+00857         /* Restart the Phy Clock */
+00858         dwc_write_reg32(core_if->pcgcctl, 0);
+00859 
+00860         /* Device configuration register */
+00861         init_devspd(core_if);
+00862         dcfg.d32 = dwc_read_reg32(&dev_if->dev_global_regs->dcfg);
+00863         dcfg.b.descdma = (core_if->dma_desc_enable) ? 1 : 0;
+00864         dcfg.b.perfrint = DWC_DCFG_FRAME_INTERVAL_80;
+00865 
+00866         dwc_write_reg32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
+00867 
+00868         /* Configure data FIFO sizes */
+00869         if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
+00870                 DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
+00871                             core_if->total_fifo_size);
+00872                 DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
+00873                             params->dev_rx_fifo_size);
+00874                 DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
+00875                             params->dev_nperio_tx_fifo_size);
+00876 
+00877                 /* Rx FIFO */
+00878                 DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
+00879                             dwc_read_reg32(&global_regs->grxfsiz));
+00880 
+00881 #ifdef DWC_UTE_CFI
+00882                 core_if->pwron_rxfsiz = dwc_read_reg32(&global_regs->grxfsiz);
+00883                 core_if->init_rxfsiz = params->dev_rx_fifo_size;
+00884 #endif
+00885                 rx_fifo_size = params->dev_rx_fifo_size;
+00886                 dwc_write_reg32(&global_regs->grxfsiz, rx_fifo_size);
+00887 
+00888                 DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
+00889                             dwc_read_reg32(&global_regs->grxfsiz));
+00890 
+00892                 core_if->p_tx_msk = 0;
+00893 
+00895                 core_if->tx_msk = 0;
+00896 
+00897                 if (core_if->en_multiple_tx_fifo == 0) {
+00898                         /* Non-periodic Tx FIFO */
+00899                         DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
+00900                                     dwc_read_reg32(&global_regs->gnptxfsiz));
+00901 
+00902                         nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
+00903                         nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
+00904 
+00905                         dwc_write_reg32(&global_regs->gnptxfsiz,
+00906                                         nptxfifosize.d32);
+00907 
+00908                         DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
+00909                                     dwc_read_reg32(&global_regs->gnptxfsiz));
+00910 
+00912                         /*
+00913                          * Periodic Tx FIFOs These FIFOs are numbered from 1 to 15.
+00914                          * Indexes of the FIFO size module parameters in the
+00915                          * dev_perio_tx_fifo_size array and the FIFO size registers in
+00916                          * the dptxfsiz array run from 0 to 14.
+00917                          */
+00919                         ptxfifosize.b.startaddr =
+00920                             nptxfifosize.b.startaddr + nptxfifosize.b.depth;
+00921                         for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep;
+00922                              i++) {
+00923                                 ptxfifosize.b.depth =
+00924                                     params->dev_perio_tx_fifo_size[i];
+00925                                 DWC_DEBUGPL(DBG_CIL,
+00926                                             "initial dptxfsiz_dieptxf[%d]=%08x\n",
+00927                                             i,
+00928                                             dwc_read_reg32(&global_regs->
+00929                                                            dptxfsiz_dieptxf
+00930                                                            [i]));
+00931                                 dwc_write_reg32(&global_regs->
+00932                                                 dptxfsiz_dieptxf[i],
+00933                                                 ptxfifosize.d32);
+00934                                 DWC_DEBUGPL(DBG_CIL,
+00935                                             "new dptxfsiz_dieptxf[%d]=%08x\n",
+00936                                             i,
+00937                                             dwc_read_reg32(&global_regs->
+00938                                                            dptxfsiz_dieptxf
+00939                                                            [i]));
+00940                                 ptxfifosize.b.startaddr += ptxfifosize.b.depth;
+00941                         }
+00942                 } else {
+00943                         /*
+00944                          * Tx FIFOs These FIFOs are numbered from 1 to 15.
+00945                          * Indexes of the FIFO size module parameters in the
+00946                          * dev_tx_fifo_size array and the FIFO size registers in
+00947                          * the dptxfsiz_dieptxf array run from 0 to 14.
+00948                          */
+00949 
+00950                         /* Non-periodic Tx FIFO */
+00951                         DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
+00952                                     dwc_read_reg32(&global_regs->gnptxfsiz));
+00953 
+00954 #ifdef DWC_UTE_CFI
+00955                         core_if->pwron_gnptxfsiz =
+00956                             (dwc_read_reg32(&global_regs->gnptxfsiz) >> 16);
+00957                         core_if->init_gnptxfsiz =
+00958                             params->dev_nperio_tx_fifo_size;
+00959 #endif
+00960                         nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
+00961                         nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
+00962 
+00963                         dwc_write_reg32(&global_regs->gnptxfsiz,
+00964                                         nptxfifosize.d32);
+00965 
+00966                         DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
+00967                                     dwc_read_reg32(&global_regs->gnptxfsiz));
+00968 
+00969                         txfifosize.b.startaddr =
+00970                             nptxfifosize.b.startaddr + nptxfifosize.b.depth;
+00971 
+00972                         for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) {
+00973 
+00974                                 txfifosize.b.depth =
+00975                                     params->dev_tx_fifo_size[i];
+00976 
+00977                                 DWC_DEBUGPL(DBG_CIL,
+00978                                             "initial dptxfsiz_dieptxf[%d]=%08x\n",
+00979                                             i,
+00980                                             dwc_read_reg32(&global_regs->
+00981                                                            dptxfsiz_dieptxf
+00982                                                            [i]));
+00983 
+00984 #ifdef DWC_UTE_CFI
+00985                                 core_if->pwron_txfsiz[i] =
+00986                                     (dwc_read_reg32
+00987                                      (&global_regs->dptxfsiz_dieptxf[i]) >> 16);
+00988                                 core_if->init_txfsiz[i] =
+00989                                     params->dev_tx_fifo_size[i];
+00990 #endif
+00991                                 dwc_write_reg32(&global_regs->
+00992                                                 dptxfsiz_dieptxf[i],
+00993                                                 txfifosize.d32);
+00994 
+00995                                 DWC_DEBUGPL(DBG_CIL,
+00996                                             "new dptxfsiz_dieptxf[%d]=%08x\n",
+00997                                             i,
+00998                                             dwc_read_reg32(&global_regs->
+00999                                                            dptxfsiz_dieptxf
+01000                                                            [i]));
+01001 
+01002                                 txfifosize.b.startaddr += txfifosize.b.depth;
+01003                         }
+01004                 }
+01005         }
+01006         /* Flush the FIFOs */
+01007         dwc_otg_flush_tx_fifo(core_if, 0x10);   /* all Tx FIFOs */
+01008         dwc_otg_flush_rx_fifo(core_if);
+01009 
+01010         /* Flush the Learning Queue. */
+01011         resetctl.b.intknqflsh = 1;
+01012         dwc_write_reg32(&core_if->core_global_regs->grstctl, resetctl.d32);
+01013 
+01014         /* Clear all pending Device Interrupts */
+01018         if (core_if->multiproc_int_enable) {
+01019                 for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
+01020                         dwc_write_reg32(&dev_if->dev_global_regs->
+01021                                         diepeachintmsk[i], 0);
+01022                 }
+01023 
+01024                 for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
+01025                         dwc_write_reg32(&dev_if->dev_global_regs->
+01026                                         doepeachintmsk[i], 0);
+01027                 }
+01028 
+01029                 dwc_write_reg32(&dev_if->dev_global_regs->deachint, 0xFFFFFFFF);
+01030                 dwc_write_reg32(&dev_if->dev_global_regs->deachintmsk, 0);
+01031         } else {
+01032                 dwc_write_reg32(&dev_if->dev_global_regs->diepmsk, 0);
+01033                 dwc_write_reg32(&dev_if->dev_global_regs->doepmsk, 0);
+01034                 dwc_write_reg32(&dev_if->dev_global_regs->daint, 0xFFFFFFFF);
+01035                 dwc_write_reg32(&dev_if->dev_global_regs->daintmsk, 0);
+01036         }
+01037 
+01038         for (i = 0; i <= dev_if->num_in_eps; i++) {
+01039                 depctl_data_t depctl;
+01040                 depctl.d32 = dwc_read_reg32(&dev_if->in_ep_regs[i]->diepctl);
+01041                 if (depctl.b.epena) {
+01042                         depctl.d32 = 0;
+01043                         depctl.b.epdis = 1;
+01044                         depctl.b.snak = 1;
+01045                 } else {
+01046                         depctl.d32 = 0;
+01047                 }
+01048 
+01049                 dwc_write_reg32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
+01050 
+01051                 dwc_write_reg32(&dev_if->in_ep_regs[i]->dieptsiz, 0);
+01052                 dwc_write_reg32(&dev_if->in_ep_regs[i]->diepdma, 0);
+01053                 dwc_write_reg32(&dev_if->in_ep_regs[i]->diepint, 0xFF);
+01054         }
+01055 
+01056         for (i = 0; i <= dev_if->num_out_eps; i++) {
+01057                 depctl_data_t depctl;
+01058                 depctl.d32 = dwc_read_reg32(&dev_if->out_ep_regs[i]->doepctl);
+01059                 if (depctl.b.epena) {
+01060                         depctl.d32 = 0;
+01061                         depctl.b.epdis = 1;
+01062                         depctl.b.snak = 1;
+01063                 } else {
+01064                         depctl.d32 = 0;
+01065                 }
+01066 
+01067                 dwc_write_reg32(&dev_if->out_ep_regs[i]->doepctl, depctl.d32);
+01068 
+01069                 dwc_write_reg32(&dev_if->out_ep_regs[i]->doeptsiz, 0);
+01070                 dwc_write_reg32(&dev_if->out_ep_regs[i]->doepdma, 0);
+01071                 dwc_write_reg32(&dev_if->out_ep_regs[i]->doepint, 0xFF);
+01072         }
+01073 
+01074         if (core_if->en_multiple_tx_fifo && core_if->dma_enable) {
+01075                 dev_if->non_iso_tx_thr_en = params->thr_ctl & 0x1;
+01076                 dev_if->iso_tx_thr_en = (params->thr_ctl >> 1) & 0x1;
+01077                 dev_if->rx_thr_en = (params->thr_ctl >> 2) & 0x1;
+01078 
+01079                 dev_if->rx_thr_length = params->rx_thr_length;
+01080                 dev_if->tx_thr_length = params->tx_thr_length;
+01081 
+01082                 dev_if->setup_desc_index = 0;
+01083 
+01084                 dthrctl.d32 = 0;
+01085                 dthrctl.b.non_iso_thr_en = dev_if->non_iso_tx_thr_en;
+01086                 dthrctl.b.iso_thr_en = dev_if->iso_tx_thr_en;
+01087                 dthrctl.b.tx_thr_len = dev_if->tx_thr_length;
+01088                 dthrctl.b.rx_thr_en = dev_if->rx_thr_en;
+01089                 dthrctl.b.rx_thr_len = dev_if->rx_thr_length;
+01090                 dthrctl.b.ahb_thr_ratio = params->ahb_thr_ratio;
+01091 
+01092                 dwc_write_reg32(&dev_if->dev_global_regs->dtknqr3_dthrctl,
+01093                                 dthrctl.d32);
+01094 
+01095                 DWC_DEBUGPL(DBG_CIL,
+01096                             "Non ISO Tx Thr - %d\nISO Tx Thr - %d\nRx Thr - %d\nTx Thr Len - %d\nRx Thr Len - %d\n",
+01097                             dthrctl.b.non_iso_thr_en, dthrctl.b.iso_thr_en,
+01098                             dthrctl.b.rx_thr_en, dthrctl.b.tx_thr_len,
+01099                             dthrctl.b.rx_thr_len);
+01100 
+01101         }
+01102 
+01103         dwc_otg_enable_device_interrupts(core_if);
+01104 
+01105         {
+01106                 diepmsk_data_t msk = {.d32 = 0 };
+01107                 msk.b.txfifoundrn = 1;
+01108                 if (core_if->multiproc_int_enable) {
+01109                         dwc_modify_reg32(&dev_if->dev_global_regs->
+01110                                          diepeachintmsk[0], msk.d32, msk.d32);
+01111                 } else {
+01112                         dwc_modify_reg32(&dev_if->dev_global_regs->diepmsk,
+01113                                          msk.d32, msk.d32);
+01114                 }
+01115         }
+01116 
+01117         if (core_if->multiproc_int_enable) {
+01118                 /* Set NAK on Babble */
+01119                 dctl_data_t dctl = {.d32 = 0 };
+01120                 dctl.b.nakonbble = 1;
+01121                 dwc_modify_reg32(&dev_if->dev_global_regs->dctl, 0, dctl.d32);
+01122         }
+01123 }
+01124 
+01130 void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * core_if)
+01131 {
+01132         dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+01133         gintmsk_data_t intr_mask = {.d32 = 0 };
+01134 
+01135         DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__);
+01136 
+01137         /* Disable all interrupts. */
+01138         dwc_write_reg32(&global_regs->gintmsk, 0);
+01139 
+01140         /* Clear any pending interrupts. */
+01141         dwc_write_reg32(&global_regs->gintsts, 0xFFFFFFFF);
+01142 
+01143         /* Enable the common interrupts */
+01144         dwc_otg_enable_common_interrupts(core_if);
+01145 
+01146         /*
+01147          * Enable host mode interrupts without disturbing common
+01148          * interrupts.
+01149          */
+01150          
+01151         /* Do not need sof interrupt for Descriptor DMA*/ 
+01152         if (!core_if->dma_desc_enable) 
+01153         intr_mask.b.sofintr = 1;
+01154         intr_mask.b.portintr = 1;
+01155         intr_mask.b.hcintr = 1;
+01156 
+01157         dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
+01158 }
+01159 
+01165 void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * core_if)
+01166 {
+01167         dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+01168         gintmsk_data_t intr_mask = {.d32 = 0 };
+01169 
+01170         DWC_DEBUGPL(DBG_CILV, "%s()\n", __func__);
+01171 
+01172         /*
+01173          * Disable host mode interrupts without disturbing common
+01174          * interrupts.
+01175          */
+01176         intr_mask.b.sofintr = 1;
+01177         intr_mask.b.portintr = 1;
+01178         intr_mask.b.hcintr = 1;
+01179         intr_mask.b.ptxfempty = 1;
+01180         intr_mask.b.nptxfempty = 1;
+01181 
+01182         dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, 0);
+01183 }
+01184 
+01196 void dwc_otg_core_host_init(dwc_otg_core_if_t * core_if)
+01197 {
+01198         dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+01199         dwc_otg_host_if_t *host_if = core_if->host_if;
+01200         dwc_otg_core_params_t *params = core_if->core_params;
+01201         hprt0_data_t hprt0 = {.d32 = 0 };
+01202         fifosize_data_t nptxfifosize;
+01203         fifosize_data_t ptxfifosize;
+01204         int i;
+01205         hcchar_data_t hcchar;
+01206         hcfg_data_t hcfg;
+01207         dwc_otg_hc_regs_t *hc_regs;
+01208         int num_channels;
+01209         gotgctl_data_t gotgctl = {.d32 = 0 };
+01210 
+01211         DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if);
+01212 
+01213         /* Restart the Phy Clock */
+01214         dwc_write_reg32(core_if->pcgcctl, 0);
+01215 
+01216         /* Initialize Host Configuration Register */
+01217         init_fslspclksel(core_if);
+01218         if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
+01219                 hcfg.d32 = dwc_read_reg32(&host_if->host_global_regs->hcfg);
+01220                 hcfg.b.fslssupp = 1;
+01221                 dwc_write_reg32(&host_if->host_global_regs->hcfg, hcfg.d32);
+01222                 
+01223         }
+01224 
+01225         if (core_if->core_params->dma_desc_enable) {
+01226                 uint8_t op_mode = core_if->hwcfg2.b.op_mode;    
+01227                 if (!(core_if->hwcfg4.b.desc_dma && (core_if->snpsid >= OTG_CORE_REV_2_90a) &&
+01228                                 ((op_mode == DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) ||
+01229                                 (op_mode == DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG) || 
+01230                                 (op_mode == DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG) ||
+01231                                 (op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST) ||
+01232                                 (op_mode == DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST)))) {
+01233                                 
+01234                                 DWC_ERROR("Host can't operate in Descriptor DMA mode.\n"
+01235                                           "Either core version is below 2.90a or "
+01236                                           "GHWCFG2, GHWCFG4 registers' values do not allow Descriptor DMA in host mode.\n"
+01237                                           "To run the driver in Buffer DMA host mode set dma_desc_enable "
+01238                                           "module parameter to 0.\n");
+01239                                 return;
+01240                 }               
+01241                 hcfg.d32 = dwc_read_reg32(&host_if->host_global_regs->hcfg);
+01242                 hcfg.b.descdma = 1;
+01243                 dwc_write_reg32(&host_if->host_global_regs->hcfg, hcfg.d32);
+01244         }
+01245         
+01246         /* Configure data FIFO sizes */
+01247         if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
+01248                 DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
+01249                             core_if->total_fifo_size);
+01250                 DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
+01251                             params->host_rx_fifo_size);
+01252                 DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
+01253                             params->host_nperio_tx_fifo_size);
+01254                 DWC_DEBUGPL(DBG_CIL, "P Tx FIFO Size=%d\n",
+01255                             params->host_perio_tx_fifo_size);
+01256 
+01257                 /* Rx FIFO */
+01258                 DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
+01259                             dwc_read_reg32(&global_regs->grxfsiz));
+01260                 dwc_write_reg32(&global_regs->grxfsiz,
+01261                                 params->host_rx_fifo_size);
+01262                 DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
+01263                             dwc_read_reg32(&global_regs->grxfsiz));
+01264 
+01265                 /* Non-periodic Tx FIFO */
+01266                 DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
+01267                             dwc_read_reg32(&global_regs->gnptxfsiz));
+01268                 nptxfifosize.b.depth = params->host_nperio_tx_fifo_size;
+01269                 nptxfifosize.b.startaddr = params->host_rx_fifo_size;
+01270                 dwc_write_reg32(&global_regs->gnptxfsiz, nptxfifosize.d32);
+01271                 DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
+01272                             dwc_read_reg32(&global_regs->gnptxfsiz));
+01273 
+01274                 /* Periodic Tx FIFO */
+01275                 DWC_DEBUGPL(DBG_CIL, "initial hptxfsiz=%08x\n",
+01276                             dwc_read_reg32(&global_regs->hptxfsiz));
+01277                 ptxfifosize.b.depth = params->host_perio_tx_fifo_size;
+01278                 ptxfifosize.b.startaddr =
+01279                     nptxfifosize.b.startaddr + nptxfifosize.b.depth;
+01280                 dwc_write_reg32(&global_regs->hptxfsiz, ptxfifosize.d32);
+01281                 DWC_DEBUGPL(DBG_CIL, "new hptxfsiz=%08x\n",
+01282                             dwc_read_reg32(&global_regs->hptxfsiz));
+01283         }
+01284 
+01285         /* Clear Host Set HNP Enable in the OTG Control Register */
+01286         gotgctl.b.hstsethnpen = 1;
+01287         dwc_modify_reg32(&global_regs->gotgctl, gotgctl.d32, 0);
+01288 
+01289         /* Make sure the FIFOs are flushed. */
+01290         dwc_otg_flush_tx_fifo(core_if, 0x10 /* all Tx FIFOs */ );
+01291         dwc_otg_flush_rx_fifo(core_if);
+01292 
+01293         if(!core_if->core_params->dma_desc_enable) {
+01294                 /* Flush out any leftover queued requests. */
+01295                 num_channels = core_if->core_params->host_channels;
+01296         
+01297                 for (i = 0; i < num_channels; i++) {
+01298                         hc_regs = core_if->host_if->hc_regs[i];
+01299                         hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01300                         hcchar.b.chen = 0;
+01301                         hcchar.b.chdis = 1;
+01302                         hcchar.b.epdir = 0;
+01303                         dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+01304                 }
+01305 
+01306                 /* Halt all channels to put them into a known state. */
+01307                 for (i = 0; i < num_channels; i++) {
+01308                         int count = 0;
+01309                         hc_regs = core_if->host_if->hc_regs[i];
+01310                         hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01311                         hcchar.b.chen = 1;
+01312                         hcchar.b.chdis = 1;
+01313                         hcchar.b.epdir = 0;
+01314                         dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+01315                         DWC_DEBUGPL(DBG_HCDV, "%s: Halt channel %d\n", __func__, i);
+01316                         do {
+01317                                 hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01318                                 if (++count > 1000) {
+01319                                         DWC_ERROR
+01320                                             ("%s: Unable to clear halt on channel %d\n",
+01321                                              __func__, i);
+01322                                         break;
+01323                                 }
+01324                                 dwc_udelay(1);
+01325                         } while (hcchar.b.chen);
+01326                 }
+01327         }
+01328         
+01329         /* Turn on the vbus power. */
+01330         DWC_PRINTF("Init: Port Power? op_state=%d\n", core_if->op_state);
+01331         if (core_if->op_state == A_HOST) {
+01332                 hprt0.d32 = dwc_otg_read_hprt0(core_if);
+01333                 DWC_PRINTF("Init: Power Port (%d)\n", hprt0.b.prtpwr);
+01334                 if (hprt0.b.prtpwr == 0) {
+01335                         hprt0.b.prtpwr = 1;
+01336                         dwc_write_reg32(host_if->hprt0, hprt0.d32);
+01337                 }
+01338         }
+01339 
+01340         dwc_otg_enable_host_interrupts(core_if);
+01341 }
+01342 
+01352 void dwc_otg_hc_init(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
+01353 {
+01354         uint32_t intr_enable;
+01355         hcintmsk_data_t hc_intr_mask;
+01356         gintmsk_data_t gintmsk = {.d32 = 0 };
+01357         hcchar_data_t hcchar;
+01358         hcsplt_data_t hcsplt;
+01359 
+01360         uint8_t hc_num = hc->hc_num;
+01361         dwc_otg_host_if_t *host_if = core_if->host_if;
+01362         dwc_otg_hc_regs_t *hc_regs = host_if->hc_regs[hc_num];
+01363 
+01364         /* Clear old interrupt conditions for this host channel. */
+01365         hc_intr_mask.d32 = 0xFFFFFFFF;
+01366         hc_intr_mask.b.reserved14_31 = 0;
+01367         dwc_write_reg32(&hc_regs->hcint, hc_intr_mask.d32);
+01368 
+01369         /* Enable channel interrupts required for this transfer. */
+01370         hc_intr_mask.d32 = 0;
+01371         hc_intr_mask.b.chhltd = 1;
+01372         if (core_if->dma_enable) {
+01373                 /* For Descriptor DMA mode core halts the channel on AHB error. Interrupt is not required */
+01374                 if (!core_if->dma_desc_enable)
+01375                         hc_intr_mask.b.ahberr = 1;
+01376                 else {
+01377                         if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) 
+01378                                 hc_intr_mask.b.xfercompl = 1;
+01379                 }
+01380                 
+01381                 if (hc->error_state && !hc->do_split &&
+01382                     hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
+01383                         hc_intr_mask.b.ack = 1;
+01384                         if (hc->ep_is_in) {
+01385                                 hc_intr_mask.b.datatglerr = 1;
+01386                                 if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
+01387                                         hc_intr_mask.b.nak = 1;
+01388                                 }
+01389                         }
+01390                 }
+01391         } else {
+01392                 switch (hc->ep_type) {
+01393                 case DWC_OTG_EP_TYPE_CONTROL:
+01394                 case DWC_OTG_EP_TYPE_BULK:
+01395                         hc_intr_mask.b.xfercompl = 1;
+01396                         hc_intr_mask.b.stall = 1;
+01397                         hc_intr_mask.b.xacterr = 1;
+01398                         hc_intr_mask.b.datatglerr = 1;
+01399                         if (hc->ep_is_in) {
+01400                                 hc_intr_mask.b.bblerr = 1;
+01401                         } else {
+01402                                 hc_intr_mask.b.nak = 1;
+01403                                 hc_intr_mask.b.nyet = 1;
+01404                                 if (hc->do_ping) {
+01405                                         hc_intr_mask.b.ack = 1;
+01406                                 }
+01407                         }
+01408 
+01409                         if (hc->do_split) {
+01410                                 hc_intr_mask.b.nak = 1;
+01411                                 if (hc->complete_split) {
+01412                                         hc_intr_mask.b.nyet = 1;
+01413                                 } else {
+01414                                         hc_intr_mask.b.ack = 1;
+01415                                 }
+01416                         }
+01417 
+01418                         if (hc->error_state) {
+01419                                 hc_intr_mask.b.ack = 1;
+01420                         }
+01421                         break;
+01422                 case DWC_OTG_EP_TYPE_INTR:
+01423                         hc_intr_mask.b.xfercompl = 1;
+01424                         hc_intr_mask.b.nak = 1;
+01425                         hc_intr_mask.b.stall = 1;
+01426                         hc_intr_mask.b.xacterr = 1;
+01427                         hc_intr_mask.b.datatglerr = 1;
+01428                         hc_intr_mask.b.frmovrun = 1;
+01429 
+01430                         if (hc->ep_is_in) {
+01431                                 hc_intr_mask.b.bblerr = 1;
+01432                         }
+01433                         if (hc->error_state) {
+01434                                 hc_intr_mask.b.ack = 1;
+01435                         }
+01436                         if (hc->do_split) {
+01437                                 if (hc->complete_split) {
+01438                                         hc_intr_mask.b.nyet = 1;
+01439                                 } else {
+01440                                         hc_intr_mask.b.ack = 1;
+01441                                 }
+01442                         }
+01443                         break;
+01444                 case DWC_OTG_EP_TYPE_ISOC:
+01445                         hc_intr_mask.b.xfercompl = 1;
+01446                         hc_intr_mask.b.frmovrun = 1;
+01447                         hc_intr_mask.b.ack = 1;
+01448 
+01449                         if (hc->ep_is_in) {
+01450                                 hc_intr_mask.b.xacterr = 1;
+01451                                 hc_intr_mask.b.bblerr = 1;
+01452                         }
+01453                         break;
+01454                 }
+01455         }
+01456         dwc_write_reg32(&hc_regs->hcintmsk, hc_intr_mask.d32);
+01457 
+01458         /* Enable the top level host channel interrupt. */
+01459         intr_enable = (1 << hc_num);
+01460         dwc_modify_reg32(&host_if->host_global_regs->haintmsk, 0, intr_enable);
+01461 
+01462         /* Make sure host channel interrupts are enabled. */
+01463         gintmsk.b.hcintr = 1;
+01464         dwc_modify_reg32(&core_if->core_global_regs->gintmsk, 0, gintmsk.d32);
+01465 
+01466         /*
+01467          * Program the HCCHARn register with the endpoint characteristics for
+01468          * the current transfer.
+01469          */
+01470         hcchar.d32 = 0;
+01471         hcchar.b.devaddr = hc->dev_addr;
+01472         hcchar.b.epnum = hc->ep_num;
+01473         hcchar.b.epdir = hc->ep_is_in;
+01474         hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
+01475         hcchar.b.eptype = hc->ep_type;
+01476         hcchar.b.mps = hc->max_packet;
+01477 
+01478         dwc_write_reg32(&host_if->hc_regs[hc_num]->hcchar, hcchar.d32);
+01479 
+01480         DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
+01481         DWC_DEBUGPL(DBG_HCDV, "  Dev Addr: %d\n", hcchar.b.devaddr);
+01482         DWC_DEBUGPL(DBG_HCDV, "  Ep Num: %d\n", hcchar.b.epnum);
+01483         DWC_DEBUGPL(DBG_HCDV, "  Is In: %d\n", hcchar.b.epdir);
+01484         DWC_DEBUGPL(DBG_HCDV, "  Is Low Speed: %d\n", hcchar.b.lspddev);
+01485         DWC_DEBUGPL(DBG_HCDV, "  Ep Type: %d\n", hcchar.b.eptype);
+01486         DWC_DEBUGPL(DBG_HCDV, "  Max Pkt: %d\n", hcchar.b.mps);
+01487         DWC_DEBUGPL(DBG_HCDV, "  Multi Cnt: %d\n", hcchar.b.multicnt);
+01488 
+01489         /*
+01490          * Program the HCSPLIT register for SPLITs
+01491          */
+01492         hcsplt.d32 = 0;
+01493         if (hc->do_split) {
+01494                 DWC_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n",
+01495                             hc->hc_num,
+01496                             hc->complete_split ? "CSPLIT" : "SSPLIT");
+01497                 hcsplt.b.compsplt = hc->complete_split;
+01498                 hcsplt.b.xactpos = hc->xact_pos;
+01499                 hcsplt.b.hubaddr = hc->hub_addr;
+01500                 hcsplt.b.prtaddr = hc->port_addr;
+01501                 DWC_DEBUGPL(DBG_HCDV, "   comp split %d\n", hc->complete_split);
+01502                 DWC_DEBUGPL(DBG_HCDV, "   xact pos %d\n", hc->xact_pos);
+01503                 DWC_DEBUGPL(DBG_HCDV, "   hub addr %d\n", hc->hub_addr);
+01504                 DWC_DEBUGPL(DBG_HCDV, "   port addr %d\n", hc->port_addr);
+01505                 DWC_DEBUGPL(DBG_HCDV, "   is_in %d\n", hc->ep_is_in);
+01506                 DWC_DEBUGPL(DBG_HCDV, "   Max Pkt: %d\n", hcchar.b.mps);
+01507                 DWC_DEBUGPL(DBG_HCDV, "   xferlen: %d\n", hc->xfer_len);
+01508         }
+01509         dwc_write_reg32(&host_if->hc_regs[hc_num]->hcsplt, hcsplt.d32);
+01510 
+01511 }
+01512 
+01540 void dwc_otg_hc_halt(dwc_otg_core_if_t * core_if,
+01541                      dwc_hc_t * hc, dwc_otg_halt_status_e halt_status)
+01542 {
+01543         gnptxsts_data_t nptxsts;
+01544         hptxsts_data_t hptxsts;
+01545         hcchar_data_t hcchar;
+01546         dwc_otg_hc_regs_t *hc_regs;
+01547         dwc_otg_core_global_regs_t *global_regs;
+01548         dwc_otg_host_global_regs_t *host_global_regs;
+01549 
+01550         hc_regs = core_if->host_if->hc_regs[hc->hc_num];
+01551         global_regs = core_if->core_global_regs;
+01552         host_global_regs = core_if->host_if->host_global_regs;
+01553 
+01554         DWC_ASSERT(!(halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS),
+01555                    "halt_status = %d\n", halt_status);
+01556 
+01557         if (halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
+01558             halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
+01559                 /*
+01560                  * Disable all channel interrupts except Ch Halted. The QTD
+01561                  * and QH state associated with this transfer has been cleared
+01562                  * (in the case of URB_DEQUEUE), so the channel needs to be
+01563                  * shut down carefully to prevent crashes.
+01564                  */
+01565                 hcintmsk_data_t hcintmsk;
+01566                 hcintmsk.d32 = 0;
+01567                 hcintmsk.b.chhltd = 1;
+01568                 dwc_write_reg32(&hc_regs->hcintmsk, hcintmsk.d32);
+01569 
+01570                 /*
+01571                  * Make sure no other interrupts besides halt are currently
+01572                  * pending. Handling another interrupt could cause a crash due
+01573                  * to the QTD and QH state.
+01574                  */
+01575                 dwc_write_reg32(&hc_regs->hcint, ~hcintmsk.d32);
+01576 
+01577                 /*
+01578                  * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
+01579                  * even if the channel was already halted for some other
+01580                  * reason.
+01581                  */
+01582                 hc->halt_status = halt_status;
+01583 
+01584                 hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01585                 if (hcchar.b.chen == 0) {
+01586                         /*
+01587                          * The channel is either already halted or it hasn't
+01588                          * started yet. In DMA mode, the transfer may halt if
+01589                          * it finishes normally or a condition occurs that
+01590                          * requires driver intervention. Don't want to halt
+01591                          * the channel again. In either Slave or DMA mode,
+01592                          * it's possible that the transfer has been assigned
+01593                          * to a channel, but not started yet when an URB is
+01594                          * dequeued. Don't want to halt a channel that hasn't
+01595                          * started yet.
+01596                          */
+01597                         return;
+01598                 }
+01599         }
+01600         if (hc->halt_pending) {
+01601                 /*
+01602                  * A halt has already been issued for this channel. This might
+01603                  * happen when a transfer is aborted by a higher level in
+01604                  * the stack.
+01605                  */
+01606 #ifdef DEBUG
+01607                 DWC_PRINTF
+01608                     ("*** %s: Channel %d, _hc->halt_pending already set ***\n",
+01609                      __func__, hc->hc_num);
+01610 
+01611 #endif
+01612                 return;
+01613         }
+01614 
+01615         hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01616         
+01617         /* No need to set the bit in DDMA for disabling the channel */
+01618         //TODO check it everywhere channel is disabled          
+01619         if(!core_if->core_params->dma_desc_enable)
+01620                 hcchar.b.chen = 1;
+01621         hcchar.b.chdis = 1;
+01622         
+01623         if (!core_if->dma_enable) {
+01624                 /* Check for space in the request queue to issue the halt. */
+01625                 if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
+01626                     hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
+01627                         nptxsts.d32 = dwc_read_reg32(&global_regs->gnptxsts);
+01628                         if (nptxsts.b.nptxqspcavail == 0) {
+01629                                 hcchar.b.chen = 0;
+01630                         }
+01631                 } else {
+01632                         hptxsts.d32 =
+01633                             dwc_read_reg32(&host_global_regs->hptxsts);
+01634                         if ((hptxsts.b.ptxqspcavail == 0)
+01635                             || (core_if->queuing_high_bandwidth)) {
+01636                                 hcchar.b.chen = 0;
+01637                         }
+01638                 }
+01639         }
+01640         dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+01641 
+01642         hc->halt_status = halt_status;
+01643 
+01644         if (hcchar.b.chen) {
+01645                 hc->halt_pending = 1;
+01646                 hc->halt_on_queue = 0;
+01647         } else {
+01648                 hc->halt_on_queue = 1;
+01649         }
+01650 
+01651         DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
+01652         DWC_DEBUGPL(DBG_HCDV, "  hcchar: 0x%08x\n", hcchar.d32);
+01653         DWC_DEBUGPL(DBG_HCDV, "  halt_pending: %d\n", hc->halt_pending);
+01654         DWC_DEBUGPL(DBG_HCDV, "  halt_on_queue: %d\n", hc->halt_on_queue);
+01655         DWC_DEBUGPL(DBG_HCDV, "  halt_status: %d\n", hc->halt_status);
+01656 
+01657         return;
+01658 }
+01659 
+01667 void dwc_otg_hc_cleanup(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
+01668 {
+01669         dwc_otg_hc_regs_t *hc_regs;
+01670 
+01671         hc->xfer_started = 0;
+01672 
+01673         /*
+01674          * Clear channel interrupt enables and any unhandled channel interrupt
+01675          * conditions.
+01676          */
+01677         hc_regs = core_if->host_if->hc_regs[hc->hc_num];
+01678         dwc_write_reg32(&hc_regs->hcintmsk, 0);
+01679         dwc_write_reg32(&hc_regs->hcint, 0xFFFFFFFF);
+01680 #ifdef DEBUG
+01681         DWC_TIMER_CANCEL(core_if->hc_xfer_timer[hc->hc_num]);
+01682 #endif
+01683 }
+01684 
+01695 static inline void hc_set_even_odd_frame(dwc_otg_core_if_t * core_if,
+01696                                          dwc_hc_t * hc, hcchar_data_t * hcchar)
+01697 {
+01698         if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
+01699             hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+01700                 hfnum_data_t hfnum;
+01701                 hfnum.d32 =
+01702                     dwc_read_reg32(&core_if->host_if->host_global_regs->hfnum);
+01703 
+01704                 /* 1 if _next_ frame is odd, 0 if it's even */
+01705                 hcchar->b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1;
+01706 #ifdef DEBUG
+01707                 if (hc->ep_type == DWC_OTG_EP_TYPE_INTR && hc->do_split
+01708                     && !hc->complete_split) {
+01709                         switch (hfnum.b.frnum & 0x7) {
+01710                         case 7:
+01711                                 core_if->hfnum_7_samples++;
+01712                                 core_if->hfnum_7_frrem_accum += hfnum.b.frrem;
+01713                                 break;
+01714                         case 0:
+01715                                 core_if->hfnum_0_samples++;
+01716                                 core_if->hfnum_0_frrem_accum += hfnum.b.frrem;
+01717                                 break;
+01718                         default:
+01719                                 core_if->hfnum_other_samples++;
+01720                                 core_if->hfnum_other_frrem_accum +=
+01721                                     hfnum.b.frrem;
+01722                                 break;
+01723                         }
+01724                 }
+01725 #endif
+01726         }
+01727 }
+01728 
+01729 #ifdef DEBUG
+01730 void hc_xfer_timeout(void *ptr)
+01731 {
+01732         hc_xfer_info_t *xfer_info = (hc_xfer_info_t *) ptr;
+01733         int hc_num = xfer_info->hc->hc_num;
+01734         DWC_WARN("%s: timeout on channel %d\n", __func__, hc_num);
+01735         DWC_WARN("      start_hcchar_val 0x%08x\n",
+01736                  xfer_info->core_if->start_hcchar_val[hc_num]);
+01737 }
+01738 #endif
+01739 
+01740 void set_pid_isoc(dwc_hc_t * hc)
+01741 {
+01742         /* Set up the initial PID for the transfer. */
+01743         if (hc->speed == DWC_OTG_EP_SPEED_HIGH) {
+01744                 if (hc->ep_is_in) {
+01745                         if (hc->multi_count == 1) {
+01746                                 hc->data_pid_start =
+01747                                     DWC_OTG_HC_PID_DATA0;
+01748                         } else if (hc->multi_count == 2) {
+01749                                 hc->data_pid_start =
+01750                                     DWC_OTG_HC_PID_DATA1;
+01751                         } else {
+01752                                 hc->data_pid_start =
+01753                                     DWC_OTG_HC_PID_DATA2;
+01754                         }
+01755                 } else {
+01756                         if (hc->multi_count == 1) {
+01757                                 hc->data_pid_start =
+01758                                     DWC_OTG_HC_PID_DATA0;
+01759                         } else {
+01760                                 hc->data_pid_start =
+01761                                     DWC_OTG_HC_PID_MDATA;
+01762                         }
+01763                 }
+01764         } else {
+01765                 hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
+01766         }
+01767 }
+01768 
+01800 void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
+01801 {
+01802         hcchar_data_t hcchar;
+01803         hctsiz_data_t hctsiz;
+01804         uint16_t num_packets;
+01805         uint32_t max_hc_xfer_size = core_if->core_params->max_transfer_size;
+01806         uint16_t max_hc_pkt_count = core_if->core_params->max_packet_count;
+01807         dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
+01808 
+01809         hctsiz.d32 = 0;
+01810 
+01811         if (hc->do_ping) {
+01812                 if (!core_if->dma_enable) {
+01813                         dwc_otg_hc_do_ping(core_if, hc);
+01814                         hc->xfer_started = 1;
+01815                         return;
+01816                 } else {
+01817                         hctsiz.b.dopng = 1;
+01818                 }
+01819         }
+01820 
+01821         if (hc->do_split) {
+01822                 num_packets = 1;
+01823 
+01824                 if (hc->complete_split && !hc->ep_is_in) {
+01825                         /* For CSPLIT OUT Transfer, set the size to 0 so the
+01826                          * core doesn't expect any data written to the FIFO */
+01827                         hc->xfer_len = 0;
+01828                 } else if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) {
+01829                         hc->xfer_len = hc->max_packet;
+01830                 } else if (!hc->ep_is_in && (hc->xfer_len > 188)) {
+01831                         hc->xfer_len = 188;
+01832                 }
+01833 
+01834                 hctsiz.b.xfersize = hc->xfer_len;
+01835         } else {
+01836                 /*
+01837                  * Ensure that the transfer length and packet count will fit
+01838                  * in the widths allocated for them in the HCTSIZn register.
+01839                  */
+01840                 if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
+01841                     hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+01842                         /*
+01843                          * Make sure the transfer size is no larger than one
+01844                          * (micro)frame's worth of data. (A check was done
+01845                          * when the periodic transfer was accepted to ensure
+01846                          * that a (micro)frame's worth of data can be
+01847                          * programmed into a channel.)
+01848                          */
+01849                         uint32_t max_periodic_len =
+01850                             hc->multi_count * hc->max_packet;
+01851                         if (hc->xfer_len > max_periodic_len) {
+01852                                 hc->xfer_len = max_periodic_len;
+01853                         } else {
+01854                         }
+01855                 } else if (hc->xfer_len > max_hc_xfer_size) {
+01856                         /* Make sure that xfer_len is a multiple of max packet size. */
+01857                         hc->xfer_len = max_hc_xfer_size - hc->max_packet + 1;
+01858                 }
+01859 
+01860                 if (hc->xfer_len > 0) {
+01861                         num_packets =
+01862                             (hc->xfer_len + hc->max_packet -
+01863                              1) / hc->max_packet;
+01864                         if (num_packets > max_hc_pkt_count) {
+01865                                 num_packets = max_hc_pkt_count;
+01866                                 hc->xfer_len = num_packets * hc->max_packet;
+01867                         }
+01868                 } else {
+01869                         /* Need 1 packet for transfer length of 0. */
+01870                         num_packets = 1;
+01871                 }
+01872 
+01873                 if (hc->ep_is_in) {
+01874                         /* Always program an integral # of max packets for IN transfers. */
+01875                         hc->xfer_len = num_packets * hc->max_packet;
+01876                 }
+01877 
+01878                 if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
+01879                     hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+01880                         /*
+01881                          * Make sure that the multi_count field matches the
+01882                          * actual transfer length.
+01883                          */
+01884                         hc->multi_count = num_packets;
+01885                 }
+01886 
+01887                 if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
+01888                         set_pid_isoc(hc);
+01889 
+01890                 hctsiz.b.xfersize = hc->xfer_len;
+01891         }
+01892 
+01893         hc->start_pkt_count = num_packets;
+01894         hctsiz.b.pktcnt = num_packets;
+01895         hctsiz.b.pid = hc->data_pid_start;
+01896         dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
+01897 
+01898         DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
+01899         DWC_DEBUGPL(DBG_HCDV, "  Xfer Size: %d\n", hctsiz.b.xfersize);
+01900         DWC_DEBUGPL(DBG_HCDV, "  Num Pkts: %d\n", hctsiz.b.pktcnt);
+01901         DWC_DEBUGPL(DBG_HCDV, "  Start PID: %d\n", hctsiz.b.pid);
+01902 
+01903         if (core_if->dma_enable) {
+01904                 dwc_dma_t dma_addr;
+01905                 if (hc->align_buff) {
+01906                         dma_addr = hc->align_buff;
+01907                 } else {
+01908                         dma_addr = (uint32_t)hc->xfer_buff;
+01909                 }
+01910                 dwc_write_reg32(&hc_regs->hcdma, dma_addr);
+01911         }
+01912 
+01913         /* Start the split */
+01914         if (hc->do_split) {
+01915                 hcsplt_data_t hcsplt;
+01916                 hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt);
+01917                 hcsplt.b.spltena = 1;
+01918                 dwc_write_reg32(&hc_regs->hcsplt, hcsplt.d32);
+01919         }
+01920 
+01921         hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01922         hcchar.b.multicnt = hc->multi_count;
+01923         hc_set_even_odd_frame(core_if, hc, &hcchar);
+01924 #ifdef DEBUG
+01925         core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
+01926         if (hcchar.b.chdis) {
+01927                 DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
+01928                          __func__, hc->hc_num, hcchar.d32);
+01929         }
+01930 #endif
+01931 
+01932         /* Set host channel enable after all other setup is complete. */
+01933         hcchar.b.chen = 1;
+01934         hcchar.b.chdis = 0;
+01935         dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+01936 
+01937         hc->xfer_started = 1;
+01938         hc->requests++;
+01939 
+01940         if (!core_if->dma_enable && !hc->ep_is_in && hc->xfer_len > 0) {
+01941                 /* Load OUT packet into the appropriate Tx FIFO. */
+01942                 dwc_otg_hc_write_packet(core_if, hc);
+01943         }
+01944 #ifdef DEBUG
+01945         if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) {
+01946                 core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
+01947                 core_if->hc_xfer_info[hc->hc_num].hc = hc;
+01948                 /* Start a timer for this transfer. */
+01949                 DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
+01950         }
+01951 #endif
+01952 }
+01953 
+01968 void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
+01969 {
+01970         dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];     
+01971         hcchar_data_t hcchar;
+01972         hctsiz_data_t hctsiz;
+01973         hcdma_data_t  hcdma;
+01974         
+01975         hctsiz.d32 = 0;
+01976 
+01977         if (hc->do_ping && !hc->ep_is_in)
+01978                 hctsiz.b_ddma.dopng = 1;
+01979 
+01980         if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)
+01981                 set_pid_isoc(hc);
+01982         
+01983         /* Packet Count and Xfer Size are not used in Descriptor DMA mode */
+01984         hctsiz.b_ddma.pid = hc->data_pid_start;
+01985         hctsiz.b_ddma.ntd = hc->ntd - 1; /* 0 - 1 descriptor, 1 - 2 descriptors, etc. */
+01986         hctsiz.b_ddma.schinfo = hc->schinfo; /* Non-zero only for high-speed interrupt endpoints */
+01987         
+01988         DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
+01989         DWC_DEBUGPL(DBG_HCDV, "  Start PID: %d\n", hctsiz.b.pid);
+01990         DWC_DEBUGPL(DBG_HCDV, "  NTD: %d\n", hctsiz.b_ddma.ntd);        
+01991 
+01992         dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
+01993 
+01994         hcdma.d32 = 0;
+01995         hcdma.b.dma_addr = ((uint32_t)hc->desc_list_addr) >> 11;
+01996                 
+01997         /* Always start from first descriptor. */
+01998         hcdma.b.ctd = 0;
+01999         dwc_write_reg32(&hc_regs->hcdma, hcdma.d32);
+02000 
+02001         hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+02002         hcchar.b.multicnt = hc->multi_count;
+02003         
+02004 #ifdef DEBUG
+02005         core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
+02006         if (hcchar.b.chdis) {
+02007                 DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
+02008                          __func__, hc->hc_num, hcchar.d32);
+02009         }
+02010 #endif
+02011 
+02012         /* Set host channel enable after all other setup is complete. */
+02013         hcchar.b.chen = 1;
+02014         hcchar.b.chdis = 0;
+02015         
+02016         dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+02017 
+02018         hc->xfer_started = 1;
+02019         hc->requests++;
+02020         
+02021 #ifdef DEBUG
+02022         if ((hc->ep_type != DWC_OTG_EP_TYPE_INTR) && (hc->ep_type != DWC_OTG_EP_TYPE_ISOC)) {
+02023                 core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
+02024                 core_if->hc_xfer_info[hc->hc_num].hc = hc;
+02025                 /* Start a timer for this transfer. */
+02026                 DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000);
+02027         }
+02028 
+02029 #endif
+02030         
+02031 }
+02032         
+02048 int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
+02049 {
+02050         DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
+02051 
+02052         if (hc->do_split) {
+02053                 /* SPLITs always queue just once per channel */
+02054                 return 0;
+02055         } else if (hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
+02056                 /* SETUPs are queued only once since they can't be NAKed. */
+02057                 return 0;
+02058         } else if (hc->ep_is_in) {
+02059                 /*
+02060                  * Always queue another request for other IN transfers. If
+02061                  * back-to-back INs are issued and NAKs are received for both,
+02062                  * the driver may still be processing the first NAK when the
+02063                  * second NAK is received. When the interrupt handler clears
+02064                  * the NAK interrupt for the first NAK, the second NAK will
+02065                  * not be seen. So we can't depend on the NAK interrupt
+02066                  * handler to requeue a NAKed request. Instead, IN requests
+02067                  * are issued each time this function is called. When the
+02068                  * transfer completes, the extra requests for the channel will
+02069                  * be flushed.
+02070                  */
+02071                 hcchar_data_t hcchar;
+02072                 dwc_otg_hc_regs_t *hc_regs =
+02073                     core_if->host_if->hc_regs[hc->hc_num];
+02074 
+02075                 hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+02076                 hc_set_even_odd_frame(core_if, hc, &hcchar);
+02077                 hcchar.b.chen = 1;
+02078                 hcchar.b.chdis = 0;
+02079                 DWC_DEBUGPL(DBG_HCDV, "  IN xfer: hcchar = 0x%08x\n",
+02080                             hcchar.d32);
+02081                 dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+02082                 hc->requests++;
+02083                 return 1;
+02084         } else {
+02085                 /* OUT transfers. */
+02086                 if (hc->xfer_count < hc->xfer_len) {
+02087                         if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
+02088                             hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+02089                                 hcchar_data_t hcchar;
+02090                                 dwc_otg_hc_regs_t *hc_regs;
+02091                                 hc_regs = core_if->host_if->hc_regs[hc->hc_num];
+02092                                 hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+02093                                 hc_set_even_odd_frame(core_if, hc, &hcchar);
+02094                         }
+02095 
+02096                         /* Load OUT packet into the appropriate Tx FIFO. */
+02097                         dwc_otg_hc_write_packet(core_if, hc);
+02098                         hc->requests++;
+02099                         return 1;
+02100                 } else {
+02101                         return 0;
+02102                 }
+02103         }
+02104 }
+02105 
+02110 void dwc_otg_hc_do_ping(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
+02111 {
+02112         hcchar_data_t hcchar;
+02113         hctsiz_data_t hctsiz;
+02114         dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
+02115 
+02116         DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
+02117 
+02118         hctsiz.d32 = 0;
+02119         hctsiz.b.dopng = 1;
+02120         hctsiz.b.pktcnt = 1;
+02121         dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
+02122 
+02123         hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+02124         hcchar.b.chen = 1;
+02125         hcchar.b.chdis = 0;
+02126         dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+02127 }
+02128 
+02129 /*
+02130  * This function writes a packet into the Tx FIFO associated with the Host
+02131  * Channel. For a channel associated with a non-periodic EP, the non-periodic
+02132  * Tx FIFO is written. For a channel associated with a periodic EP, the
+02133  * periodic Tx FIFO is written. This function should only be called in Slave
+02134  * mode.
+02135  *
+02136  * Upon return the xfer_buff and xfer_count fields in _hc are incremented by
+02137  * then number of bytes written to the Tx FIFO.
+02138  */
+02139 void dwc_otg_hc_write_packet(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
+02140 {
+02141         uint32_t i;
+02142         uint32_t remaining_count;
+02143         uint32_t byte_count;
+02144         uint32_t dword_count;
+02145 
+02146         uint32_t *data_buff = (uint32_t *) (hc->xfer_buff);
+02147         uint32_t *data_fifo = core_if->data_fifo[hc->hc_num];
+02148 
+02149         remaining_count = hc->xfer_len - hc->xfer_count;
+02150         if (remaining_count > hc->max_packet) {
+02151                 byte_count = hc->max_packet;
+02152         } else {
+02153                 byte_count = remaining_count;
+02154         }
+02155 
+02156         dword_count = (byte_count + 3) / 4;
+02157 
+02158         if ((((unsigned long)data_buff) & 0x3) == 0) {
+02159                 /* xfer_buff is DWORD aligned. */
+02160                 for (i = 0; i < dword_count; i++, data_buff++) {
+02161                         dwc_write_reg32(data_fifo, *data_buff);
+02162                 }
+02163         } else {
+02164                 /* xfer_buff is not DWORD aligned. */
+02165                 for (i = 0; i < dword_count; i++, data_buff++) {
+02166                         uint32_t data;
+02167                         data =
+02168                             (data_buff[0] | data_buff[1] << 8 | data_buff[2] <<
+02169                              16 | data_buff[3] << 24);
+02170                         dwc_write_reg32(data_fifo, data);
+02171                 }
+02172         }
+02173 
+02174         hc->xfer_count += byte_count;
+02175         hc->xfer_buff += byte_count;
+02176 }
+02177 
+02182 uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * core_if)
+02183 {
+02184         dsts_data_t dsts;
+02185         dsts.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
+02186 
+02187         /* read current frame/microframe number from DSTS register */
+02188         return dsts.b.soffn;
+02189 }
+02190 
+02199 void dwc_otg_read_setup_packet(dwc_otg_core_if_t * core_if, uint32_t * dest)
+02200 {
+02201         /* Get the 8 bytes of a setup transaction data */
+02202 
+02203         /* Pop 2 DWORDS off the receive data FIFO into memory */
+02204         dest[0] = dwc_read_reg32(core_if->data_fifo[0]);
+02205         dest[1] = dwc_read_reg32(core_if->data_fifo[0]);
+02206 }
+02207 
+02216 void dwc_otg_ep0_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+02217 {
+02218         dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+02219         dsts_data_t dsts;
+02220         depctl_data_t diepctl;
+02221         depctl_data_t doepctl;
+02222         dctl_data_t dctl = {.d32 = 0 };
+02223 
+02224         /* Read the Device Status and Endpoint 0 Control registers */
+02225         dsts.d32 = dwc_read_reg32(&dev_if->dev_global_regs->dsts);
+02226         diepctl.d32 = dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl);
+02227         doepctl.d32 = dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl);
+02228 
+02229         /* Set the MPS of the IN EP based on the enumeration speed */
+02230         switch (dsts.b.enumspd) {
+02231         case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
+02232         case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
+02233         case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
+02234                 diepctl.b.mps = DWC_DEP0CTL_MPS_64;
+02235                 break;
+02236         case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
+02237                 diepctl.b.mps = DWC_DEP0CTL_MPS_8;
+02238                 break;
+02239         }
+02240 
+02241         dwc_write_reg32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
+02242 
+02243         /* Enable OUT EP for receive */
+02244         doepctl.b.epena = 1;
+02245         dwc_write_reg32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
+02246 
+02247 #ifdef VERBOSE
+02248         DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
+02249                     dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl));
+02250         DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
+02251                     dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl));
+02252 #endif
+02253         dctl.b.cgnpinnak = 1;
+02254 
+02255         dwc_modify_reg32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
+02256         DWC_DEBUGPL(DBG_PCDV, "dctl=%0x\n",
+02257                     dwc_read_reg32(&dev_if->dev_global_regs->dctl));
+02258 }
+02259 
+02268 void dwc_otg_ep_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+02269 {
+02270         dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+02271         depctl_data_t depctl;
+02272         volatile uint32_t *addr;
+02273         daint_data_t daintmsk = {.d32 = 0 };
+02274 
+02275         DWC_DEBUGPL(DBG_PCDV, "%s() EP%d-%s\n", __func__, ep->num,
+02276                     (ep->is_in ? "IN" : "OUT"));
+02277 
+02278         /* Read DEPCTLn register */
+02279         if (ep->is_in == 1) {
+02280                 addr = &dev_if->in_ep_regs[ep->num]->diepctl;
+02281                 daintmsk.ep.in = 1 << ep->num;
+02282         } else {
+02283                 addr = &dev_if->out_ep_regs[ep->num]->doepctl;
+02284                 daintmsk.ep.out = 1 << ep->num;
+02285         }
+02286 
+02287         /* If the EP is already active don't change the EP Control
+02288          * register. */
+02289         depctl.d32 = dwc_read_reg32(addr);
+02290         if (!depctl.b.usbactep) {
+02291                 depctl.b.mps = ep->maxpacket;
+02292                 depctl.b.eptype = ep->type;
+02293                 depctl.b.txfnum = ep->tx_fifo_num;
+02294 
+02295                 if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
+02296                         depctl.b.setd0pid = 1;  // ??? 
+02297                 } else {
+02298                         depctl.b.setd0pid = 1;
+02299                 }
+02300                 depctl.b.usbactep = 1;
+02301 
+02302                 dwc_write_reg32(addr, depctl.d32);
+02303                 DWC_DEBUGPL(DBG_PCDV, "DEPCTL=%08x\n", dwc_read_reg32(addr));
+02304         }
+02305 
+02306         /* Enable the Interrupt for this EP */
+02307         if (core_if->multiproc_int_enable) {
+02308                 if (ep->is_in == 1) {
+02309                         diepmsk_data_t diepmsk = {.d32 = 0 };
+02310                         diepmsk.b.xfercompl = 1;
+02311                         diepmsk.b.timeout = 1;
+02312                         diepmsk.b.epdisabled = 1;
+02313                         diepmsk.b.ahberr = 1;
+02314                         diepmsk.b.intknepmis = 1;
+02315                         diepmsk.b.txfifoundrn = 1;      //?????
+02316 
+02317                         if (core_if->dma_desc_enable) {
+02318                                 diepmsk.b.bna = 1;
+02319                         }
+02320 /*                      
+02321                         if(core_if->dma_enable) {
+02322                                 doepmsk.b.nak = 1;
+02323                         }
+02324 */
+02325                         dwc_write_reg32(&dev_if->dev_global_regs->
+02326                                         diepeachintmsk[ep->num], diepmsk.d32);
+02327 
+02328                 } else {
+02329                         doepmsk_data_t doepmsk = {.d32 = 0 };
+02330                         doepmsk.b.xfercompl = 1;
+02331                         doepmsk.b.ahberr = 1;
+02332                         doepmsk.b.epdisabled = 1;
+02333 
+02334                         if (core_if->dma_desc_enable) {
+02335                                 doepmsk.b.bna = 1;
+02336                         }
+02337 /*                      
+02338                         doepmsk.b.babble = 1;
+02339                         doepmsk.b.nyet = 1;
+02340                         doepmsk.b.nak = 1;
+02341 */
+02342                         dwc_write_reg32(&dev_if->dev_global_regs->
+02343                                         doepeachintmsk[ep->num], doepmsk.d32);
+02344                 }
+02345                 dwc_modify_reg32(&dev_if->dev_global_regs->deachintmsk,
+02346                                  0, daintmsk.d32);
+02347         } else {
+02348                 dwc_modify_reg32(&dev_if->dev_global_regs->daintmsk,
+02349                                  0, daintmsk.d32);
+02350         }
+02351 
+02352         DWC_DEBUGPL(DBG_PCDV, "DAINTMSK=%0x\n",
+02353                     dwc_read_reg32(&dev_if->dev_global_regs->daintmsk));
+02354 
+02355         ep->stall_clear_flag = 0;
+02356         return;
+02357 }
+02358 
+02367 void dwc_otg_ep_deactivate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+02368 {
+02369         depctl_data_t depctl = {.d32 = 0 };
+02370         volatile uint32_t *addr;
+02371         daint_data_t daintmsk = {.d32 = 0 };
+02372 
+02373         /* Read DEPCTLn register */
+02374         if (ep->is_in == 1) {
+02375                 addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
+02376                 daintmsk.ep.in = 1 << ep->num;
+02377         } else {
+02378                 addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
+02379                 daintmsk.ep.out = 1 << ep->num;
+02380         }
+02381 
+02382         depctl.d32 = dwc_read_reg32(addr);
+02383 
+02384         depctl.b.usbactep = 0;
+02385 
+02386         if (core_if->dma_desc_enable)
+02387                 depctl.b.epdis = 1;
+02388 
+02389         dwc_write_reg32(addr, depctl.d32);
+02390 
+02391         /* Disable the Interrupt for this EP */
+02392         if (core_if->multiproc_int_enable) {
+02393                 dwc_modify_reg32(&core_if->dev_if->dev_global_regs->deachintmsk,
+02394                                  daintmsk.d32, 0);
+02395 
+02396                 if (ep->is_in == 1) {
+02397                         dwc_write_reg32(&core_if->dev_if->dev_global_regs->
+02398                                         diepeachintmsk[ep->num], 0);
+02399                 } else {
+02400                         dwc_write_reg32(&core_if->dev_if->dev_global_regs->
+02401                                         doepeachintmsk[ep->num], 0);
+02402                 }
+02403         } else {
+02404                 dwc_modify_reg32(&core_if->dev_if->dev_global_regs->daintmsk,
+02405                                  daintmsk.d32, 0);
+02406         }
+02407 }
+02408 
+02415 static void init_dma_desc_chain(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+02416 {
+02417         dwc_otg_dev_dma_desc_t *dma_desc;
+02418         uint32_t offset;
+02419         uint32_t xfer_est;
+02420         int i;
+02421 
+02422         ep->desc_cnt = (ep->total_len / ep->maxxfer) +
+02423             ((ep->total_len % ep->maxxfer) ? 1 : 0);
+02424         if (!ep->desc_cnt)
+02425                 ep->desc_cnt = 1;
+02426 
+02427         dma_desc = ep->desc_addr;
+02428         xfer_est = ep->total_len;
+02429         offset = 0;
+02430         for (i = 0; i < ep->desc_cnt; ++i) {
+02432                 if (xfer_est > ep->maxxfer) {
+02433                         dma_desc->status.b.bs = BS_HOST_BUSY;
+02434                         dma_desc->status.b.l = 0;
+02435                         dma_desc->status.b.ioc = 0;
+02436                         dma_desc->status.b.sp = 0;
+02437                         dma_desc->status.b.bytes = ep->maxxfer;
+02438                         dma_desc->buf = ep->dma_addr + offset;
+02439                         dma_desc->status.b.bs = BS_HOST_READY;
+02440 
+02441                         xfer_est -= ep->maxxfer;
+02442                         offset += ep->maxxfer;
+02443                 } else {
+02444                         dma_desc->status.b.bs = BS_HOST_BUSY;
+02445                         dma_desc->status.b.l = 1;
+02446                         dma_desc->status.b.ioc = 1;
+02447                         if (ep->is_in) {
+02448                                 dma_desc->status.b.sp =
+02449                                     (xfer_est %
+02450                                      ep->maxpacket) ? 1 : ((ep->
+02451                                                             sent_zlp) ? 1 : 0);
+02452                                 dma_desc->status.b.bytes = xfer_est;
+02453                         } else {
+02454                                 dma_desc->status.b.bytes =
+02455                                     xfer_est + ((4 - (xfer_est & 0x3)) & 0x3);
+02456                         }
+02457 
+02458                         dma_desc->buf = ep->dma_addr + offset;
+02459                         dma_desc->status.b.bs = BS_HOST_READY;
+02460                 }
+02461                 dma_desc++;
+02462         }
+02463 }
+02464 
+02475 void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+02476 {
+02477         depctl_data_t depctl;
+02478         deptsiz_data_t deptsiz;
+02479         gintmsk_data_t intr_mask = {.d32 = 0 };
+02480 
+02481         DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
+02482         DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
+02483                     "xfer_buff=%p start_xfer_buff=%p, total_len = %d\n",
+02484                     ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
+02485                     ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff,
+02486                     ep->total_len);
+02487         /* IN endpoint */
+02488         if (ep->is_in == 1) {
+02489                 dwc_otg_dev_in_ep_regs_t *in_regs =
+02490                     core_if->dev_if->in_ep_regs[ep->num];
+02491 
+02492                 gnptxsts_data_t gtxstatus;
+02493 
+02494                 gtxstatus.d32 =
+02495                     dwc_read_reg32(&core_if->core_global_regs->gnptxsts);
+02496 
+02497                 if (core_if->en_multiple_tx_fifo == 0
+02498                     && gtxstatus.b.nptxqspcavail == 0) {
+02499 #ifdef DEBUG
+02500                         DWC_PRINTF("TX Queue Full (0x%0x)\n", gtxstatus.d32);
+02501 #endif
+02502                         return;
+02503                 }
+02504 
+02505                 depctl.d32 = dwc_read_reg32(&(in_regs->diepctl));
+02506                 deptsiz.d32 = dwc_read_reg32(&(in_regs->dieptsiz));
+02507 
+02508                 ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
+02509                     ep->maxxfer : (ep->total_len - ep->xfer_len);
+02510 
+02511                 /* Zero Length Packet? */
+02512                 if ((ep->xfer_len - ep->xfer_count) == 0) {
+02513                         deptsiz.b.xfersize = 0;
+02514                         deptsiz.b.pktcnt = 1;
+02515                 } else {
+02516                         /* Program the transfer size and packet count
+02517                          *      as follows: xfersize = N * maxpacket +
+02518                          *      short_packet pktcnt = N + (short_packet
+02519                          *      exist ? 1 : 0)  
+02520                          */
+02521                         deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
+02522                         deptsiz.b.pktcnt =
+02523                             (ep->xfer_len - ep->xfer_count - 1 +
+02524                              ep->maxpacket) / ep->maxpacket;
+02525                 }
+02526 
+02527                 /* Write the DMA register */
+02528                 if (core_if->dma_enable) {
+02529                         if (core_if->dma_desc_enable == 0) {
+02530                                 dwc_write_reg32(&in_regs->dieptsiz,
+02531                                                 deptsiz.d32);
+02532                                 dwc_write_reg32(&(in_regs->diepdma),
+02533                                                 (uint32_t) ep->dma_addr);
+02534                         } else {
+02535 #ifdef DWC_UTE_CFI
+02536                                 /* The descriptor chain should be already initialized by now */
+02537                                 if (ep->buff_mode != BM_STANDARD) {
+02538                                         dwc_write_reg32(&in_regs->diepdma,
+02539                                                         ep->descs_dma_addr);
+02540                                 } else {
+02541 #endif
+02542                                 init_dma_desc_chain(core_if, ep);
+02544                                 dwc_write_reg32(&in_regs->diepdma,
+02545                                                 ep->dma_desc_addr);
+02546 #ifdef DWC_UTE_CFI
+02547                         }
+02548 #endif
+02549                         }
+02550                 } else {
+02551                         dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32);
+02552                         if (ep->type != DWC_OTG_EP_TYPE_ISOC) {
+02558                                 if (core_if->en_multiple_tx_fifo == 0) {
+02559                                         intr_mask.b.nptxfempty = 1;
+02560                                         dwc_modify_reg32(&core_if->
+02561                                                          core_global_regs->
+02562                                                          gintmsk, intr_mask.d32,
+02563                                                          intr_mask.d32);
+02564                                 } else {
+02565                                         /* Enable the Tx FIFO Empty Interrupt for this EP */
+02566                                         if (ep->xfer_len > 0) {
+02567                                                 uint32_t fifoemptymsk = 0;
+02568                                                 fifoemptymsk = 1 << ep->num;
+02569                                                 dwc_modify_reg32(&core_if->
+02570                                                                  dev_if->
+02571                                                                  dev_global_regs->
+02572                                                                  dtknqr4_fifoemptymsk,
+02573                                                                  0,
+02574                                                                  fifoemptymsk);
+02575 
+02576                                         }
+02577                                 }
+02578                         }
+02579                 }
+02580 
+02581                 /* EP enable, IN data in FIFO */
+02582                 depctl.b.cnak = 1;
+02583                 depctl.b.epena = 1;
+02584                 dwc_write_reg32(&in_regs->diepctl, depctl.d32);
+02585 
+02586                 depctl.d32 =
+02587                     dwc_read_reg32(&core_if->dev_if->in_ep_regs[0]->diepctl);
+02588                 depctl.b.nextep = ep->num;
+02589                 dwc_write_reg32(&core_if->dev_if->in_ep_regs[0]->diepctl,
+02590                                 depctl.d32);
+02591 
+02592         } else {
+02593                 /* OUT endpoint */
+02594                 dwc_otg_dev_out_ep_regs_t *out_regs =
+02595                     core_if->dev_if->out_ep_regs[ep->num];
+02596 
+02597                 depctl.d32 = dwc_read_reg32(&(out_regs->doepctl));
+02598                 deptsiz.d32 = dwc_read_reg32(&(out_regs->doeptsiz));
+02599 
+02600                 ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ?
+02601                     ep->maxxfer : (ep->total_len - ep->xfer_len);
+02602 
+02603                 /* Program the transfer size and packet count as follows:
+02604                  * 
+02605                  *      pktcnt = N                                                                                 
+02606                  *      xfersize = N * maxpacket
+02607                  */
+02608                 if ((ep->xfer_len - ep->xfer_count) == 0) {
+02609                         /* Zero Length Packet */
+02610                         deptsiz.b.xfersize = ep->maxpacket;
+02611                         deptsiz.b.pktcnt = 1;
+02612                 } else {
+02613                         deptsiz.b.pktcnt =
+02614                             (ep->xfer_len - ep->xfer_count +
+02615                              (ep->maxpacket - 1)) / ep->maxpacket;
+02616                         ep->xfer_len =
+02617                             deptsiz.b.pktcnt * ep->maxpacket + ep->xfer_count;
+02618                         deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count;
+02619                 }
+02620 
+02621                 DWC_DEBUGPL(DBG_PCDV, "ep%d xfersize=%d pktcnt=%d\n",
+02622                             ep->num, deptsiz.b.xfersize, deptsiz.b.pktcnt);
+02623 
+02624                 if (core_if->dma_enable) {
+02625                         if (!core_if->dma_desc_enable) {
+02626                                 dwc_write_reg32(&out_regs->doeptsiz,
+02627                                                 deptsiz.d32);
+02628 
+02629                                 dwc_write_reg32(&(out_regs->doepdma),
+02630                                                 (uint32_t) ep->dma_addr);
+02631                         } else {
+02632 #ifdef DWC_UTE_CFI
+02633                                 /* The descriptor chain should be already initialized by now */
+02634                                 if (ep->buff_mode != BM_STANDARD) {
+02635                                         dwc_write_reg32(&out_regs->doepdma,
+02636                                                         ep->descs_dma_addr);
+02637                                 } else {
+02638 #endif
+02639 
+02640                                 init_dma_desc_chain(core_if, ep);
+02641 
+02643                                 dwc_write_reg32(&out_regs->doepdma,
+02644                                                 ep->dma_desc_addr);
+02645 #ifdef DWC_UTE_CFI
+02646                                 }
+02647 #endif
+02648                         }
+02649                 } else {
+02650                         dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32);
+02651                 }
+02652 
+02653                 /* EP enable */
+02654                 depctl.b.cnak = 1;
+02655                 depctl.b.epena = 1;
+02656 
+02657                 dwc_write_reg32(&out_regs->doepctl, depctl.d32);
+02658 
+02659                 DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n",
+02660                             dwc_read_reg32(&out_regs->doepctl),
+02661                             dwc_read_reg32(&out_regs->doeptsiz));
+02662                 DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n",
+02663                             dwc_read_reg32(&core_if->dev_if->dev_global_regs->
+02664                                            daintmsk),
+02665                             dwc_read_reg32(&core_if->core_global_regs->
+02666                                            gintmsk));
+02667         }
+02668 }
+02669 
+02678 void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+02679 {
+02680 
+02681         depctl_data_t depctl;
+02682         deptsiz_data_t deptsiz;
+02683         gintmsk_data_t intr_mask = {.d32 = 0 };
+02684 
+02685         DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
+02686         DWC_PRINTF("zero length transfer is called\n");
+02687 
+02688         /* IN endpoint */
+02689         if (ep->is_in == 1) {
+02690                 dwc_otg_dev_in_ep_regs_t *in_regs =
+02691                     core_if->dev_if->in_ep_regs[ep->num];
+02692 
+02693                 depctl.d32 = dwc_read_reg32(&(in_regs->diepctl));
+02694                 deptsiz.d32 = dwc_read_reg32(&(in_regs->dieptsiz));
+02695 
+02696                 deptsiz.b.xfersize = 0;
+02697                 deptsiz.b.pktcnt = 1;
+02698 
+02699                 /* Write the DMA register */
+02700                 if (core_if->dma_enable) {
+02701                         if (core_if->dma_desc_enable == 0) {
+02702                                 dwc_write_reg32(&in_regs->dieptsiz,
+02703                                                 deptsiz.d32);
+02704                                 dwc_write_reg32(&(in_regs->diepdma),
+02705                                                 (uint32_t) ep->dma_addr);
+02706                         }
+02707                 } else {
+02708                         dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32);
+02714                         if (core_if->en_multiple_tx_fifo == 0) {
+02715                                 intr_mask.b.nptxfempty = 1;
+02716                                 dwc_modify_reg32(&core_if->core_global_regs->
+02717                                                  gintmsk, intr_mask.d32,
+02718                                                  intr_mask.d32);
+02719                         } else {
+02720                                 /* Enable the Tx FIFO Empty Interrupt for this EP */
+02721                                 if (ep->xfer_len > 0) {
+02722                                         uint32_t fifoemptymsk = 0;
+02723                                         fifoemptymsk = 1 << ep->num;
+02724                                         dwc_modify_reg32(&core_if->dev_if->
+02725                                                          dev_global_regs->
+02726                                                          dtknqr4_fifoemptymsk,
+02727                                                          0, fifoemptymsk);
+02728                                 }
+02729                         }
+02730                 }
+02731 
+02732                 /* EP enable, IN data in FIFO */
+02733                 depctl.b.cnak = 1;
+02734                 depctl.b.epena = 1;
+02735                 dwc_write_reg32(&in_regs->diepctl, depctl.d32);
+02736 
+02737                 depctl.d32 =
+02738                     dwc_read_reg32(&core_if->dev_if->in_ep_regs[0]->diepctl);
+02739                 depctl.b.nextep = ep->num;
+02740                 dwc_write_reg32(&core_if->dev_if->in_ep_regs[0]->diepctl,
+02741                                 depctl.d32);
+02742 
+02743         } else {
+02744                 /* OUT endpoint */
+02745                 dwc_otg_dev_out_ep_regs_t *out_regs =
+02746                     core_if->dev_if->out_ep_regs[ep->num];
+02747 
+02748                 depctl.d32 = dwc_read_reg32(&(out_regs->doepctl));
+02749                 deptsiz.d32 = dwc_read_reg32(&(out_regs->doeptsiz));
+02750 
+02751                 /* Zero Length Packet */
+02752                 deptsiz.b.xfersize = ep->maxpacket;
+02753                 deptsiz.b.pktcnt = 1;
+02754 
+02755                 if (core_if->dma_enable) {
+02756                         if (!core_if->dma_desc_enable) {
+02757                                 dwc_write_reg32(&out_regs->doeptsiz,
+02758                                                 deptsiz.d32);
+02759 
+02760                                 dwc_write_reg32(&(out_regs->doepdma),
+02761                                                 (uint32_t) ep->dma_addr);
+02762                         }
+02763                 } else {
+02764                         dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32);
+02765                 }
+02766 
+02767                 /* EP enable */
+02768                 depctl.b.cnak = 1;
+02769                 depctl.b.epena = 1;
+02770 
+02771                 dwc_write_reg32(&out_regs->doepctl, depctl.d32);
+02772 
+02773         }
+02774 }
+02775 
+02785 void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+02786 {
+02787         depctl_data_t depctl;
+02788         deptsiz0_data_t deptsiz;
+02789         gintmsk_data_t intr_mask = {.d32 = 0 };
+02790         dwc_otg_dev_dma_desc_t *dma_desc;
+02791 
+02792         DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
+02793                     "xfer_buff=%p start_xfer_buff=%p \n",
+02794                     ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
+02795                     ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff);
+02796 
+02797         ep->total_len = ep->xfer_len;
+02798 
+02799         /* IN endpoint */
+02800         if (ep->is_in == 1) {
+02801                 dwc_otg_dev_in_ep_regs_t *in_regs =
+02802                     core_if->dev_if->in_ep_regs[0];
+02803 
+02804                 gnptxsts_data_t gtxstatus;
+02805 
+02806                 gtxstatus.d32 =
+02807                     dwc_read_reg32(&core_if->core_global_regs->gnptxsts);
+02808 
+02809                 if (core_if->en_multiple_tx_fifo == 0
+02810                     && gtxstatus.b.nptxqspcavail == 0) {
+02811 #ifdef DEBUG
+02812                         deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz);
+02813                         DWC_DEBUGPL(DBG_PCD, "DIEPCTL0=%0x\n",
+02814                                     dwc_read_reg32(&in_regs->diepctl));
+02815                         DWC_DEBUGPL(DBG_PCD, "DIEPTSIZ0=%0x (sz=%d, pcnt=%d)\n",
+02816                                     deptsiz.d32,
+02817                                     deptsiz.b.xfersize, deptsiz.b.pktcnt);
+02818                         DWC_PRINTF("TX Queue or FIFO Full (0x%0x)\n",
+02819                                    gtxstatus.d32);
+02820 #endif
+02821                         return;
+02822                 }
+02823 
+02824                 depctl.d32 = dwc_read_reg32(&in_regs->diepctl);
+02825                 deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz);
+02826 
+02827                 /* Zero Length Packet? */
+02828                 if (ep->xfer_len == 0) {
+02829                         deptsiz.b.xfersize = 0;
+02830                         deptsiz.b.pktcnt = 1;
+02831                 } else {
+02832                         /* Program the transfer size and packet count
+02833                          *      as follows: xfersize = N * maxpacket +
+02834                          *      short_packet pktcnt = N + (short_packet
+02835                          *      exist ? 1 : 0)  
+02836                          */
+02837                         if (ep->xfer_len > ep->maxpacket) {
+02838                                 ep->xfer_len = ep->maxpacket;
+02839                                 deptsiz.b.xfersize = ep->maxpacket;
+02840                         } else {
+02841                                 deptsiz.b.xfersize = ep->xfer_len;
+02842                         }
+02843                         deptsiz.b.pktcnt = 1;
+02844 
+02845                 }
+02846                 DWC_DEBUGPL(DBG_PCDV,
+02847                             "IN len=%d  xfersize=%d pktcnt=%d [%08x]\n",
+02848                             ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
+02849                             deptsiz.d32);
+02850 
+02851                 /* Write the DMA register */
+02852                 if (core_if->dma_enable) {
+02853                         if (core_if->dma_desc_enable == 0) {
+02854                                 dwc_write_reg32(&in_regs->dieptsiz,
+02855                                                 deptsiz.d32);
+02856 
+02857                                 dwc_write_reg32(&(in_regs->diepdma),
+02858                                                 (uint32_t) ep->dma_addr);
+02859                         } else {
+02860                                 dma_desc = core_if->dev_if->in_desc_addr;
+02861 
+02863                                 dma_desc->status.b.bs = BS_HOST_BUSY;
+02864                                 dma_desc->status.b.l = 1;
+02865                                 dma_desc->status.b.ioc = 1;
+02866                                 dma_desc->status.b.sp =
+02867                                     (ep->xfer_len == ep->maxpacket) ? 0 : 1;
+02868                                 dma_desc->status.b.bytes = ep->xfer_len;
+02869                                 dma_desc->buf = ep->dma_addr;
+02870                                 dma_desc->status.b.bs = BS_HOST_READY;
+02871 
+02873                                 dwc_write_reg32(&in_regs->diepdma,
+02874                                                 core_if->dev_if->
+02875                                                 dma_in_desc_addr);
+02876                         }
+02877                 } else {
+02878                         dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32);
+02879                 }
+02880 
+02881                 /* EP enable, IN data in FIFO */
+02882                 depctl.b.cnak = 1;
+02883                 depctl.b.epena = 1;
+02884                 dwc_write_reg32(&in_regs->diepctl, depctl.d32);
+02885 
+02890                 if (!core_if->dma_enable) {
+02891                         if (core_if->en_multiple_tx_fifo == 0) {
+02892                                 intr_mask.b.nptxfempty = 1;
+02893                                 dwc_modify_reg32(&core_if->core_global_regs->
+02894                                                  gintmsk, intr_mask.d32,
+02895                                                  intr_mask.d32);
+02896                         } else {
+02897                                 /* Enable the Tx FIFO Empty Interrupt for this EP */
+02898                                 if (ep->xfer_len > 0) {
+02899                                         uint32_t fifoemptymsk = 0;
+02900                                         fifoemptymsk |= 1 << ep->num;
+02901                                         dwc_modify_reg32(&core_if->dev_if->
+02902                                                          dev_global_regs->
+02903                                                          dtknqr4_fifoemptymsk,
+02904                                                          0, fifoemptymsk);
+02905                                 }
+02906                         }
+02907                 }
+02908         } else {
+02909                 /* OUT endpoint */
+02910                 dwc_otg_dev_out_ep_regs_t *out_regs =
+02911                     core_if->dev_if->out_ep_regs[0];
+02912 
+02913                 depctl.d32 = dwc_read_reg32(&out_regs->doepctl);
+02914                 deptsiz.d32 = dwc_read_reg32(&out_regs->doeptsiz);
+02915 
+02916                 /* Program the transfer size and packet count as follows:
+02917                  *      xfersize = N * (maxpacket + 4 - (maxpacket % 4))
+02918                  *      pktcnt = N                                                                                      */
+02919                 /* Zero Length Packet */
+02920                 deptsiz.b.xfersize = ep->maxpacket;
+02921                 deptsiz.b.pktcnt = 1;
+02922 
+02923                 DWC_DEBUGPL(DBG_PCDV, "len=%d  xfersize=%d pktcnt=%d\n",
+02924                             ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt);
+02925 
+02926                 if (core_if->dma_enable) {
+02927                         if (!core_if->dma_desc_enable) {
+02928                                 dwc_write_reg32(&out_regs->doeptsiz,
+02929                                                 deptsiz.d32);
+02930 
+02931                                 dwc_write_reg32(&(out_regs->doepdma),
+02932                                                 (uint32_t) ep->dma_addr);
+02933                         } else {
+02934                                 dma_desc = core_if->dev_if->out_desc_addr;
+02935 
+02937                                 dma_desc->status.b.bs = BS_HOST_BUSY;
+02938                                 dma_desc->status.b.l = 1;
+02939                                 dma_desc->status.b.ioc = 1;
+02940                                 dma_desc->status.b.bytes = ep->maxpacket;
+02941                                 dma_desc->buf = ep->dma_addr;
+02942                                 dma_desc->status.b.bs = BS_HOST_READY;
+02943 
+02945                                 dwc_write_reg32(&out_regs->doepdma,
+02946                                                 core_if->dev_if->
+02947                                                 dma_out_desc_addr);
+02948                         }
+02949                 } else {
+02950                         dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32);
+02951                 }
+02952 
+02953                 /* EP enable */
+02954                 depctl.b.cnak = 1;
+02955                 depctl.b.epena = 1;
+02956                 dwc_write_reg32(&(out_regs->doepctl), depctl.d32);
+02957         }
+02958 }
+02959 
+02969 void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+02970 {
+02971         depctl_data_t depctl;
+02972         deptsiz0_data_t deptsiz;
+02973         gintmsk_data_t intr_mask = {.d32 = 0 };
+02974         dwc_otg_dev_dma_desc_t *dma_desc;
+02975 
+02976         if (ep->is_in == 1) {
+02977                 dwc_otg_dev_in_ep_regs_t *in_regs =
+02978                     core_if->dev_if->in_ep_regs[0];
+02979                 gnptxsts_data_t tx_status = {.d32 = 0 };
+02980 
+02981                 tx_status.d32 =
+02982                     dwc_read_reg32(&core_if->core_global_regs->gnptxsts);
+02986                 depctl.d32 = dwc_read_reg32(&in_regs->diepctl);
+02987                 deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz);
+02988 
+02989                 /* Program the transfer size and packet count
+02990                  *      as follows: xfersize = N * maxpacket +
+02991                  *      short_packet pktcnt = N + (short_packet
+02992                  *      exist ? 1 : 0)  
+02993                  */
+02994 
+02995                 if (core_if->dma_desc_enable == 0) {
+02996                         deptsiz.b.xfersize =
+02997                             (ep->total_len - ep->xfer_count) >
+02998                             ep->maxpacket ? ep->maxpacket : (ep->total_len -
+02999                                                              ep->xfer_count);
+03000                         deptsiz.b.pktcnt = 1;
+03001                         if (core_if->dma_enable == 0) {
+03002                                 ep->xfer_len += deptsiz.b.xfersize;
+03003                         } else {
+03004                                 ep->xfer_len = deptsiz.b.xfersize;
+03005                         }
+03006                         dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32);
+03007                 } else {
+03008                         ep->xfer_len =
+03009                             (ep->total_len - ep->xfer_count) >
+03010                             ep->maxpacket ? ep->maxpacket : (ep->total_len -
+03011                                                              ep->xfer_count);
+03012 
+03013                         dma_desc = core_if->dev_if->in_desc_addr;
+03014 
+03016                         dma_desc->status.b.bs = BS_HOST_BUSY;
+03017                         dma_desc->status.b.l = 1;
+03018                         dma_desc->status.b.ioc = 1;
+03019                         dma_desc->status.b.sp =
+03020                             (ep->xfer_len == ep->maxpacket) ? 0 : 1;
+03021                         dma_desc->status.b.bytes = ep->xfer_len;
+03022                         dma_desc->buf = ep->dma_addr;
+03023                         dma_desc->status.b.bs = BS_HOST_READY;
+03024 
+03026                         dwc_write_reg32(&in_regs->diepdma,
+03027                                         core_if->dev_if->dma_in_desc_addr);
+03028                 }
+03029 
+03030                 DWC_DEBUGPL(DBG_PCDV,
+03031                             "IN len=%d  xfersize=%d pktcnt=%d [%08x]\n",
+03032                             ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
+03033                             deptsiz.d32);
+03034 
+03035                 /* Write the DMA register */
+03036                 if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
+03037                         if (core_if->dma_desc_enable == 0)
+03038                                 dwc_write_reg32(&(in_regs->diepdma),
+03039                                                 (uint32_t) ep->dma_addr);
+03040                 }
+03041 
+03042                 /* EP enable, IN data in FIFO */
+03043                 depctl.b.cnak = 1;
+03044                 depctl.b.epena = 1;
+03045                 dwc_write_reg32(&in_regs->diepctl, depctl.d32);
+03046 
+03051                 if (!core_if->dma_enable) {
+03052                         if (core_if->en_multiple_tx_fifo == 0) {
+03053                                 /* First clear it from GINTSTS */
+03054                                 intr_mask.b.nptxfempty = 1;
+03055                                 dwc_modify_reg32(&core_if->core_global_regs->
+03056                                                  gintmsk, intr_mask.d32,
+03057                                                  intr_mask.d32);
+03058 
+03059                         } else {
+03060                                 /* Enable the Tx FIFO Empty Interrupt for this EP */
+03061                                 if (ep->xfer_len > 0) {
+03062                                         uint32_t fifoemptymsk = 0;
+03063                                         fifoemptymsk |= 1 << ep->num;
+03064                                         dwc_modify_reg32(&core_if->dev_if->
+03065                                                          dev_global_regs->
+03066                                                          dtknqr4_fifoemptymsk,
+03067                                                          0, fifoemptymsk);
+03068                                 }
+03069                         }
+03070                 }
+03071         } else {
+03072                 dwc_otg_dev_out_ep_regs_t *out_regs =
+03073                     core_if->dev_if->out_ep_regs[0];
+03074 
+03075                 depctl.d32 = dwc_read_reg32(&out_regs->doepctl);
+03076                 deptsiz.d32 = dwc_read_reg32(&out_regs->doeptsiz);
+03077 
+03078                 /* Program the transfer size and packet count
+03079                  *      as follows: xfersize = N * maxpacket +
+03080                  *      short_packet pktcnt = N + (short_packet
+03081                  *      exist ? 1 : 0)  
+03082                  */
+03083                 deptsiz.b.xfersize = ep->maxpacket;
+03084                 deptsiz.b.pktcnt = 1;
+03085 
+03086                 if (core_if->dma_desc_enable == 0) {
+03087                         dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32);
+03088                 } else {
+03089                         dma_desc = core_if->dev_if->out_desc_addr;
+03090 
+03092                         dma_desc->status.b.bs = BS_HOST_BUSY;
+03093                         dma_desc->status.b.l = 1;
+03094                         dma_desc->status.b.ioc = 1;
+03095                         dma_desc->status.b.bytes = ep->maxpacket;
+03096                         dma_desc->buf = ep->dma_addr;
+03097                         dma_desc->status.b.bs = BS_HOST_READY;
+03098 
+03100                         dwc_write_reg32(&out_regs->doepdma,
+03101                                         core_if->dev_if->dma_out_desc_addr);
+03102                 }
+03103 
+03104                 DWC_DEBUGPL(DBG_PCDV,
+03105                             "IN len=%d  xfersize=%d pktcnt=%d [%08x]\n",
+03106                             ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
+03107                             deptsiz.d32);
+03108 
+03109                 /* Write the DMA register */
+03110                 if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
+03111                         if (core_if->dma_desc_enable == 0)
+03112                                 dwc_write_reg32(&(out_regs->doepdma),
+03113                                                 (uint32_t) ep->dma_addr);
+03114                 }
+03115 
+03116                 /* EP enable, IN data in FIFO */
+03117                 depctl.b.cnak = 1;
+03118                 depctl.b.epena = 1;
+03119                 dwc_write_reg32(&out_regs->doepctl, depctl.d32);
+03120 
+03121         }
+03122 }
+03123 
+03124 #ifdef DEBUG
+03125 void dump_msg(const u8 * buf, unsigned int length)
+03126 {
+03127         unsigned int start, num, i;
+03128         char line[52], *p;
+03129 
+03130         if (length >= 512)
+03131                 return;
+03132         start = 0;
+03133         while (length > 0) {
+03134                 num = length < 16u ? length : 16u;
+03135                 p = line;
+03136                 for (i = 0; i < num; ++i) {
+03137                         if (i == 8)
+03138                                 *p++ = ' ';
+03139                         DWC_SPRINTF(p, " %02x", buf[i]);
+03140                         p += 3;
+03141                 }
+03142                 *p = 0;
+03143                 DWC_PRINTF("%6x: %s\n", start, line);
+03144                 buf += num;
+03145                 start += num;
+03146                 length -= num;
+03147         }
+03148 }
+03149 #else
+03150 static inline void dump_msg(const u8 * buf, unsigned int length)
+03151 {
+03152 }
+03153 #endif
+03154 
+03165 void dwc_otg_ep_write_packet(dwc_otg_core_if_t * core_if, dwc_ep_t * ep,
+03166                              int dma)
+03167 {
+03183         uint32_t i;
+03184         uint32_t byte_count;
+03185         uint32_t dword_count;
+03186         uint32_t *fifo;
+03187         uint32_t *data_buff = (uint32_t *) ep->xfer_buff;
+03188 
+03189         DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p)\n", __func__, core_if,
+03190                     ep);
+03191         if (ep->xfer_count >= ep->xfer_len) {
+03192                 DWC_WARN("%s() No data for EP%d!!!\n", __func__, ep->num);
+03193                 return;
+03194         }
+03195 
+03196         /* Find the byte length of the packet either short packet or MPS */
+03197         if ((ep->xfer_len - ep->xfer_count) < ep->maxpacket) {
+03198                 byte_count = ep->xfer_len - ep->xfer_count;
+03199         } else {
+03200                 byte_count = ep->maxpacket;
+03201         }
+03202 
+03203         /* Find the DWORD length, padded by extra bytes as neccessary if MPS
+03204          * is not a multiple of DWORD */
+03205         dword_count = (byte_count + 3) / 4;
+03206 
+03207 #ifdef VERBOSE
+03208         dump_msg(ep->xfer_buff, byte_count);
+03209 #endif
+03210 
+03214         fifo = core_if->data_fifo[ep->num];
+03215 
+03216         DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "fifo=%p buff=%p *p=%08x bc=%d\n",
+03217                     fifo, data_buff, *data_buff, byte_count);
+03218 
+03219         if (!dma) {
+03220                 for (i = 0; i < dword_count; i++, data_buff++) {
+03221                         dwc_write_reg32(fifo, *data_buff);
+03222                 }
+03223         }
+03224 
+03225         ep->xfer_count += byte_count;
+03226         ep->xfer_buff += byte_count;
+03227         ep->dma_addr += byte_count;
+03228 }
+03229 
+03236 void dwc_otg_ep_set_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+03237 {
+03238         depctl_data_t depctl;
+03239         volatile uint32_t *depctl_addr;
+03240 
+03241         DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
+03242                     (ep->is_in ? "IN" : "OUT"));
+03243 
+03244         if (ep->is_in == 1) {
+03245                 depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
+03246                 depctl.d32 = dwc_read_reg32(depctl_addr);
+03247 
+03248                 /* set the disable and stall bits */
+03249                 if (depctl.b.epena) {
+03250                         depctl.b.epdis = 1;
+03251                 }
+03252                 depctl.b.stall = 1;
+03253                 dwc_write_reg32(depctl_addr, depctl.d32);
+03254         } else {
+03255                 depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
+03256                 depctl.d32 = dwc_read_reg32(depctl_addr);
+03257 
+03258                 /* set the stall bit */
+03259                 depctl.b.stall = 1;
+03260                 dwc_write_reg32(depctl_addr, depctl.d32);
+03261         }
+03262 
+03263         DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", dwc_read_reg32(depctl_addr));
+03264 
+03265         return;
+03266 }
+03267 
+03274 void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+03275 {
+03276         depctl_data_t depctl;
+03277         volatile uint32_t *depctl_addr;
+03278 
+03279         DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
+03280                     (ep->is_in ? "IN" : "OUT"));
+03281 
+03282         if (ep->is_in == 1) {
+03283                 depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
+03284         } else {
+03285                 depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
+03286         }
+03287 
+03288         depctl.d32 = dwc_read_reg32(depctl_addr);
+03289 
+03290         /* clear the stall bits */
+03291         depctl.b.stall = 0;
+03292 
+03293         /* 
+03294          * USB Spec 9.4.5: For endpoints using data toggle, regardless
+03295          * of whether an endpoint has the Halt feature set, a
+03296          * ClearFeature(ENDPOINT_HALT) request always results in the
+03297          * data toggle being reinitialized to DATA0.
+03298          */
+03299         if (ep->type == DWC_OTG_EP_TYPE_INTR ||
+03300             ep->type == DWC_OTG_EP_TYPE_BULK) {
+03301                 depctl.b.setd0pid = 1;  /* DATA0 */
+03302         }
+03303 
+03304         dwc_write_reg32(depctl_addr, depctl.d32);
+03305         DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", dwc_read_reg32(depctl_addr));
+03306         return;
+03307 }
+03308 
+03317 void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
+03318                          uint8_t * dest, uint16_t bytes)
+03319 {
+03320         int i;
+03321         int word_count = (bytes + 3) / 4;
+03322 
+03323         volatile uint32_t *fifo = core_if->data_fifo[0];
+03324         uint32_t *data_buff = (uint32_t *) dest;
+03325 
+03332         DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p,%d)\n", __func__,
+03333                     core_if, dest, bytes);
+03334 
+03335         for (i = 0; i < word_count; i++, data_buff++) {
+03336                 *data_buff = dwc_read_reg32(fifo);
+03337         }
+03338 
+03339         return;
+03340 }
+03341 
+03347 void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * core_if)
+03348 {
+03349         int i;
+03350         volatile uint32_t *addr;
+03351 
+03352         DWC_PRINTF("Device Global Registers\n");
+03353         addr = &core_if->dev_if->dev_global_regs->dcfg;
+03354         DWC_PRINTF("DCFG                 @0x%08X : 0x%08X\n", (uint32_t) addr,
+03355                    dwc_read_reg32(addr));
+03356         addr = &core_if->dev_if->dev_global_regs->dctl;
+03357         DWC_PRINTF("DCTL                 @0x%08X : 0x%08X\n", (uint32_t) addr,
+03358                    dwc_read_reg32(addr));
+03359         addr = &core_if->dev_if->dev_global_regs->dsts;
+03360         DWC_PRINTF("DSTS                 @0x%08X : 0x%08X\n", (uint32_t) addr,
+03361                    dwc_read_reg32(addr));
+03362         addr = &core_if->dev_if->dev_global_regs->diepmsk;
+03363         DWC_PRINTF("DIEPMSK      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03364                    dwc_read_reg32(addr));
+03365         addr = &core_if->dev_if->dev_global_regs->doepmsk;
+03366         DWC_PRINTF("DOEPMSK      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03367                    dwc_read_reg32(addr));
+03368         addr = &core_if->dev_if->dev_global_regs->daint;
+03369         DWC_PRINTF("DAINT        @0x%08X : 0x%08X\n", (uint32_t) addr,
+03370                    dwc_read_reg32(addr));
+03371         addr = &core_if->dev_if->dev_global_regs->daintmsk;
+03372         DWC_PRINTF("DAINTMSK     @0x%08X : 0x%08X\n", (uint32_t) addr,
+03373                    dwc_read_reg32(addr));
+03374         addr = &core_if->dev_if->dev_global_regs->dtknqr1;
+03375         DWC_PRINTF("DTKNQR1      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03376                    dwc_read_reg32(addr));
+03377         if (core_if->hwcfg2.b.dev_token_q_depth > 6) {
+03378                 addr = &core_if->dev_if->dev_global_regs->dtknqr2;
+03379                 DWC_PRINTF("DTKNQR2      @0x%08X : 0x%08X\n",
+03380                            (uint32_t) addr, dwc_read_reg32(addr));
+03381         }
+03382 
+03383         addr = &core_if->dev_if->dev_global_regs->dvbusdis;
+03384         DWC_PRINTF("DVBUSID      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03385                    dwc_read_reg32(addr));
+03386 
+03387         addr = &core_if->dev_if->dev_global_regs->dvbuspulse;
+03388         DWC_PRINTF("DVBUSPULSE  @0x%08X : 0x%08X\n",
+03389                    (uint32_t) addr, dwc_read_reg32(addr));
+03390 
+03391                 addr = &core_if->dev_if->dev_global_regs->dtknqr3_dthrctl;
+03392                 DWC_PRINTF("DTKNQR3_DTHRCTL      @0x%08X : 0x%08X\n",
+03393                            (uint32_t) addr, dwc_read_reg32(addr));
+03394 
+03395         if (core_if->hwcfg2.b.dev_token_q_depth > 22) {
+03396                 addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
+03397                 DWC_PRINTF("DTKNQR4      @0x%08X : 0x%08X\n",
+03398                            (uint32_t) addr, dwc_read_reg32(addr));
+03399         }
+03400 
+03401         addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk;
+03402         DWC_PRINTF("FIFOEMPMSK   @0x%08X : 0x%08X\n", (uint32_t) addr,
+03403                    dwc_read_reg32(addr));
+03404 
+03405         addr = &core_if->dev_if->dev_global_regs->deachint;
+03406         DWC_PRINTF("DEACHINT     @0x%08X : 0x%08X\n", (uint32_t) addr,
+03407                    dwc_read_reg32(addr));
+03408         addr = &core_if->dev_if->dev_global_regs->deachintmsk;
+03409         DWC_PRINTF("DEACHINTMSK  @0x%08X : 0x%08X\n", (uint32_t) addr,
+03410                    dwc_read_reg32(addr));
+03411 
+03412         for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
+03413                 addr = &core_if->dev_if->dev_global_regs->diepeachintmsk[i];
+03414                 DWC_PRINTF("DIEPEACHINTMSK[%d]   @0x%08X : 0x%08X\n", i,
+03415                            (uint32_t) addr, dwc_read_reg32(addr));
+03416         }
+03417 
+03418         for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
+03419                 addr = &core_if->dev_if->dev_global_regs->doepeachintmsk[i];
+03420                 DWC_PRINTF("DOEPEACHINTMSK[%d]   @0x%08X : 0x%08X\n", i,
+03421                            (uint32_t) addr, dwc_read_reg32(addr));
+03422         }
+03423 
+03424         for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
+03425                 DWC_PRINTF("Device IN EP %d Registers\n", i);
+03426                 addr = &core_if->dev_if->in_ep_regs[i]->diepctl;
+03427                 DWC_PRINTF("DIEPCTL      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03428                            dwc_read_reg32(addr));
+03429                 addr = &core_if->dev_if->in_ep_regs[i]->diepint;
+03430                 DWC_PRINTF("DIEPINT      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03431                            dwc_read_reg32(addr));
+03432                 addr = &core_if->dev_if->in_ep_regs[i]->dieptsiz;
+03433                 DWC_PRINTF("DIETSIZ      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03434                            dwc_read_reg32(addr));
+03435                 addr = &core_if->dev_if->in_ep_regs[i]->diepdma;
+03436                 DWC_PRINTF("DIEPDMA      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03437                            dwc_read_reg32(addr));
+03438                 addr = &core_if->dev_if->in_ep_regs[i]->dtxfsts;
+03439                 DWC_PRINTF("DTXFSTS      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03440                            dwc_read_reg32(addr));
+03441                 addr = &core_if->dev_if->in_ep_regs[i]->diepdmab;
+03442                 DWC_PRINTF("DIEPDMAB     @0x%08X : 0x%08X\n", (uint32_t) addr,
+03443                            0 /*dwc_read_reg32(addr) */ );
+03444         }
+03445 
+03446         for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
+03447                 DWC_PRINTF("Device OUT EP %d Registers\n", i);
+03448                 addr = &core_if->dev_if->out_ep_regs[i]->doepctl;
+03449                 DWC_PRINTF("DOEPCTL      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03450                            dwc_read_reg32(addr));
+03451                 addr = &core_if->dev_if->out_ep_regs[i]->doepfn;
+03452                 DWC_PRINTF("DOEPFN       @0x%08X : 0x%08X\n", (uint32_t) addr,
+03453                            dwc_read_reg32(addr));
+03454                 addr = &core_if->dev_if->out_ep_regs[i]->doepint;
+03455                 DWC_PRINTF("DOEPINT      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03456                            dwc_read_reg32(addr));
+03457                 addr = &core_if->dev_if->out_ep_regs[i]->doeptsiz;
+03458                 DWC_PRINTF("DOETSIZ      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03459                            dwc_read_reg32(addr));
+03460                 addr = &core_if->dev_if->out_ep_regs[i]->doepdma;
+03461                 DWC_PRINTF("DOEPDMA      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03462                            dwc_read_reg32(addr));
+03463                 if (core_if->dma_enable) {      /* Don't access this register in SLAVE mode */
+03464                         addr = &core_if->dev_if->out_ep_regs[i]->doepdmab;
+03465                         DWC_PRINTF("DOEPDMAB     @0x%08X : 0x%08X\n",
+03466                                    (uint32_t) addr, dwc_read_reg32(addr));
+03467                 }
+03468 
+03469         }
+03470 }
+03471 
+03477 void dwc_otg_dump_spram(dwc_otg_core_if_t * core_if)
+03478 {
+03479         volatile uint8_t *addr, *start_addr, *end_addr;
+03480 
+03481         DWC_PRINTF("SPRAM Data:\n");
+03482         start_addr = (void *)core_if->core_global_regs;
+03483         DWC_PRINTF("Base Address: 0x%8X\n", (uint32_t) start_addr);
+03484         start_addr += 0x00028000;
+03485         end_addr = (void *)core_if->core_global_regs;
+03486         end_addr += 0x000280e0;
+03487 
+03488         for (addr = start_addr; addr < end_addr; addr += 16) {
+03489                 DWC_PRINTF
+03490                     ("0x%8X:\t%2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X\n",
+03491                      (uint32_t) addr, addr[0], addr[1], addr[2], addr[3],
+03492                      addr[4], addr[5], addr[6], addr[7], addr[8], addr[9],
+03493                      addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]
+03494                     );
+03495         }
+03496 
+03497         return;
+03498 }
+03499 
+03505 void dwc_otg_dump_host_registers(dwc_otg_core_if_t * core_if)
+03506 {
+03507         int i;
+03508         volatile uint32_t *addr;
+03509 
+03510         DWC_PRINTF("Host Global Registers\n");
+03511         addr = &core_if->host_if->host_global_regs->hcfg;
+03512         DWC_PRINTF("HCFG                 @0x%08X : 0x%08X\n", (uint32_t) addr,
+03513                    dwc_read_reg32(addr));
+03514         addr = &core_if->host_if->host_global_regs->hfir;
+03515         DWC_PRINTF("HFIR                 @0x%08X : 0x%08X\n", (uint32_t) addr,
+03516                    dwc_read_reg32(addr));
+03517         addr = &core_if->host_if->host_global_regs->hfnum;
+03518         DWC_PRINTF("HFNUM        @0x%08X : 0x%08X\n", (uint32_t) addr,
+03519                    dwc_read_reg32(addr));
+03520         addr = &core_if->host_if->host_global_regs->hptxsts;
+03521         DWC_PRINTF("HPTXSTS      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03522                    dwc_read_reg32(addr));
+03523         addr = &core_if->host_if->host_global_regs->haint;
+03524         DWC_PRINTF("HAINT        @0x%08X : 0x%08X\n", (uint32_t) addr,
+03525                    dwc_read_reg32(addr));
+03526         addr = &core_if->host_if->host_global_regs->haintmsk;
+03527         DWC_PRINTF("HAINTMSK     @0x%08X : 0x%08X\n", (uint32_t) addr,
+03528                    dwc_read_reg32(addr));
+03529         if (core_if->dma_desc_enable) {
+03530                 addr = &core_if->host_if->host_global_regs->hflbaddr;
+03531                 DWC_PRINTF("HFLBADDR     @0x%08X : 0x%08X\n",(uint32_t) addr,
+03532                            dwc_read_reg32(addr));
+03533         }
+03534         
+03535         addr = core_if->host_if->hprt0;
+03536         DWC_PRINTF("HPRT0        @0x%08X : 0x%08X\n", (uint32_t) addr,
+03537                    dwc_read_reg32(addr));
+03538 
+03539         for (i = 0; i < core_if->core_params->host_channels; i++) {
+03540                 DWC_PRINTF("Host Channel %d Specific Registers\n", i);
+03541                 addr = &core_if->host_if->hc_regs[i]->hcchar;
+03542                 DWC_PRINTF("HCCHAR       @0x%08X : 0x%08X\n", (uint32_t) addr,
+03543                            dwc_read_reg32(addr));
+03544                 addr = &core_if->host_if->hc_regs[i]->hcsplt;
+03545                 DWC_PRINTF("HCSPLT       @0x%08X : 0x%08X\n", (uint32_t) addr,
+03546                            dwc_read_reg32(addr));
+03547                 addr = &core_if->host_if->hc_regs[i]->hcint;
+03548                 DWC_PRINTF("HCINT        @0x%08X : 0x%08X\n", (uint32_t) addr,
+03549                            dwc_read_reg32(addr));
+03550                 addr = &core_if->host_if->hc_regs[i]->hcintmsk;
+03551                 DWC_PRINTF("HCINTMSK     @0x%08X : 0x%08X\n", (uint32_t) addr,
+03552                            dwc_read_reg32(addr));
+03553                 addr = &core_if->host_if->hc_regs[i]->hctsiz;
+03554                 DWC_PRINTF("HCTSIZ       @0x%08X : 0x%08X\n", (uint32_t) addr,
+03555                            dwc_read_reg32(addr));
+03556                 addr = &core_if->host_if->hc_regs[i]->hcdma;
+03557                 DWC_PRINTF("HCDMA        @0x%08X : 0x%08X\n", (uint32_t) addr,
+03558                            dwc_read_reg32(addr));
+03559                 if (core_if->dma_desc_enable) {
+03560                         addr=&core_if->host_if->hc_regs[i]->hcdmab;
+03561                         DWC_PRINTF("HCDMAB       @0x%08X : 0x%08X\n",(uint32_t) addr, dwc_read_reg32(addr));
+03562         }
+03563 
+03564         }
+03565         return;
+03566 }
+03567 
+03573 void dwc_otg_dump_global_registers(dwc_otg_core_if_t * core_if)
+03574 {
+03575         int i;
+03576         volatile uint32_t *addr;
+03577 
+03578         DWC_PRINTF("Core Global Registers\n");
+03579         addr = &core_if->core_global_regs->gotgctl;
+03580         DWC_PRINTF("GOTGCTL      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03581                    dwc_read_reg32(addr));
+03582         addr = &core_if->core_global_regs->gotgint;
+03583         DWC_PRINTF("GOTGINT      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03584                    dwc_read_reg32(addr));
+03585         addr = &core_if->core_global_regs->gahbcfg;
+03586         DWC_PRINTF("GAHBCFG      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03587                    dwc_read_reg32(addr));
+03588         addr = &core_if->core_global_regs->gusbcfg;
+03589         DWC_PRINTF("GUSBCFG      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03590                    dwc_read_reg32(addr));
+03591         addr = &core_if->core_global_regs->grstctl;
+03592         DWC_PRINTF("GRSTCTL      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03593                    dwc_read_reg32(addr));
+03594         addr = &core_if->core_global_regs->gintsts;
+03595         DWC_PRINTF("GINTSTS      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03596                    dwc_read_reg32(addr));
+03597         addr = &core_if->core_global_regs->gintmsk;
+03598         DWC_PRINTF("GINTMSK      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03599                    dwc_read_reg32(addr));
+03600         addr = &core_if->core_global_regs->grxstsr;
+03601         DWC_PRINTF("GRXSTSR      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03602                    dwc_read_reg32(addr));
+03603         addr = &core_if->core_global_regs->grxfsiz;
+03604         DWC_PRINTF("GRXFSIZ      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03605                    dwc_read_reg32(addr));
+03606         addr = &core_if->core_global_regs->gnptxfsiz;
+03607         DWC_PRINTF("GNPTXFSIZ @0x%08X : 0x%08X\n", (uint32_t) addr,
+03608                    dwc_read_reg32(addr));
+03609         addr = &core_if->core_global_regs->gnptxsts;
+03610         DWC_PRINTF("GNPTXSTS     @0x%08X : 0x%08X\n", (uint32_t) addr,
+03611                    dwc_read_reg32(addr));
+03612         addr = &core_if->core_global_regs->gi2cctl;
+03613         DWC_PRINTF("GI2CCTL      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03614                    dwc_read_reg32(addr));
+03615         addr = &core_if->core_global_regs->gpvndctl;
+03616         DWC_PRINTF("GPVNDCTL     @0x%08X : 0x%08X\n", (uint32_t) addr,
+03617                    dwc_read_reg32(addr));
+03618         addr = &core_if->core_global_regs->ggpio;
+03619         DWC_PRINTF("GGPIO        @0x%08X : 0x%08X\n", (uint32_t) addr,
+03620                    dwc_read_reg32(addr));
+03621         addr = &core_if->core_global_regs->guid;
+03622         DWC_PRINTF("GUID                 @0x%08X : 0x%08X\n", (uint32_t) addr,
+03623                    dwc_read_reg32(addr));
+03624         addr = &core_if->core_global_regs->gsnpsid;
+03625         DWC_PRINTF("GSNPSID      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03626                    dwc_read_reg32(addr));
+03627         addr = &core_if->core_global_regs->ghwcfg1;
+03628         DWC_PRINTF("GHWCFG1      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03629                    dwc_read_reg32(addr));
+03630         addr = &core_if->core_global_regs->ghwcfg2;
+03631         DWC_PRINTF("GHWCFG2      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03632                    dwc_read_reg32(addr));
+03633         addr = &core_if->core_global_regs->ghwcfg3;
+03634         DWC_PRINTF("GHWCFG3      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03635                    dwc_read_reg32(addr));
+03636         addr = &core_if->core_global_regs->ghwcfg4;
+03637         DWC_PRINTF("GHWCFG4      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03638                    dwc_read_reg32(addr));
+03639         addr = &core_if->core_global_regs->glpmcfg;
+03640         DWC_PRINTF("GLPMCFG      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03641                    dwc_read_reg32(addr));
+03642         addr = &core_if->core_global_regs->hptxfsiz;
+03643         DWC_PRINTF("HPTXFSIZ     @0x%08X : 0x%08X\n", (uint32_t) addr,
+03644                    dwc_read_reg32(addr));
+03645 
+03646         for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
+03647                 addr = &core_if->core_global_regs->dptxfsiz_dieptxf[i];
+03648                 DWC_PRINTF("DPTXFSIZ[%d] @0x%08X : 0x%08X\n", i,
+03649                            (uint32_t) addr, dwc_read_reg32(addr));
+03650         }
+03651         addr = core_if->pcgcctl;
+03652         DWC_PRINTF("PCGCCTL      @0x%08X : 0x%08X\n", (uint32_t) addr,
+03653                    dwc_read_reg32(addr));
+03654 }
+03655 
+03662 void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * core_if, const int num)
+03663 {
+03664         dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+03665         volatile grstctl_t greset = {.d32 = 0 };
+03666         int count = 0;
+03667 
+03668         DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "Flush Tx FIFO %d\n", num);
+03669 
+03670         greset.b.txfflsh = 1;
+03671         greset.b.txfnum = num;
+03672         dwc_write_reg32(&global_regs->grstctl, greset.d32);
+03673 
+03674         do {
+03675                 greset.d32 = dwc_read_reg32(&global_regs->grstctl);
+03676                 if (++count > 10000) {
+03677                         DWC_WARN("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n",
+03678                                  __func__, greset.d32,
+03679                                  dwc_read_reg32(&global_regs->gnptxsts));
+03680                         break;
+03681                 }
+03682                 dwc_udelay(1);
+03683         } while (greset.b.txfflsh == 1);
+03684 
+03685         /* Wait for 3 PHY Clocks */
+03686         dwc_udelay(1);
+03687 }
+03688 
+03694 void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * core_if)
+03695 {
+03696         dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+03697         volatile grstctl_t greset = {.d32 = 0 };
+03698         int count = 0;
+03699 
+03700         DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "%s\n", __func__);
+03701         /*
+03702          * 
+03703          */
+03704         greset.b.rxfflsh = 1;
+03705         dwc_write_reg32(&global_regs->grstctl, greset.d32);
+03706 
+03707         do {
+03708                 greset.d32 = dwc_read_reg32(&global_regs->grstctl);
+03709                 if (++count > 10000) {
+03710                         DWC_WARN("%s() HANG! GRSTCTL=%0x\n", __func__,
+03711                                  greset.d32);
+03712                         break;
+03713                 }
+03714                 dwc_udelay(1);
+03715         } while (greset.b.rxfflsh == 1);
+03716 
+03717         /* Wait for 3 PHY Clocks */
+03718         dwc_udelay(1);
+03719 }
+03720 
+03725 void dwc_otg_core_reset(dwc_otg_core_if_t * core_if)
+03726 {
+03727         dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+03728         volatile grstctl_t greset = {.d32 = 0 };
+03729         int count = 0;
+03730 
+03731         DWC_DEBUGPL(DBG_CILV, "%s\n", __func__);
+03732         /* Wait for AHB master IDLE state. */
+03733         do {
+03734                 dwc_udelay(10);
+03735                 greset.d32 = dwc_read_reg32(&global_regs->grstctl);
+03736                 if (++count > 100000) {
+03737                         DWC_WARN("%s() HANG! AHB Idle GRSTCTL=%0x\n", __func__,
+03738                                  greset.d32);
+03739                         return;
+03740                 }
+03741         }
+03742         while (greset.b.ahbidle == 0);
+03743 
+03744         /* Core Soft Reset */
+03745         count = 0;
+03746         greset.b.csftrst = 1;
+03747         dwc_write_reg32(&global_regs->grstctl, greset.d32);
+03748         do {
+03749                 greset.d32 = dwc_read_reg32(&global_regs->grstctl);
+03750                 if (++count > 10000) {
+03751                         DWC_WARN("%s() HANG! Soft Reset GRSTCTL=%0x\n",
+03752                                  __func__, greset.d32);
+03753                         break;
+03754                 }
+03755                 dwc_udelay(1);
+03756         }
+03757         while (greset.b.csftrst == 1);
+03758 
+03759         /* Wait for 3 PHY Clocks */
+03760         dwc_mdelay(100);
+03761 }
+03762 
+03763 uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if)
+03764 {
+03765         return (dwc_otg_mode(_core_if) != DWC_HOST_MODE);
+03766 }
+03767 
+03768 uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if)
+03769 {
+03770         return (dwc_otg_mode(_core_if) == DWC_HOST_MODE);
+03771 }
+03772 
+03781 void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * core_if,
+03782                                         dwc_otg_cil_callbacks_t * cb, void *p)
+03783 {
+03784         core_if->hcd_cb = cb;
+03785         cb->p = p;
+03786 }
+03787 
+03796 void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * core_if,
+03797                                         dwc_otg_cil_callbacks_t * cb, void *p)
+03798 {
+03799         core_if->pcd_cb = cb;
+03800         cb->p = p;
+03801 }
+03802 
+03803 #ifdef DWC_EN_ISOC
+03804 
+03812 void write_isoc_frame_data(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+03813 {
+03814         dwc_otg_dev_in_ep_regs_t *ep_regs;
+03815         dtxfsts_data_t txstatus = {.d32 = 0 };
+03816         uint32_t len = 0;
+03817         uint32_t dwords;
+03818 
+03819         ep->xfer_len = ep->data_per_frame;
+03820         ep->xfer_count = 0;
+03821 
+03822         ep_regs = core_if->dev_if->in_ep_regs[ep->num];
+03823 
+03824         len = ep->xfer_len - ep->xfer_count;
+03825 
+03826         if (len > ep->maxpacket) {
+03827                 len = ep->maxpacket;
+03828         }
+03829 
+03830         dwords = (len + 3) / 4;
+03831 
+03832         /* While there is space in the queue and space in the FIFO and
+03833          * More data to tranfer, Write packets to the Tx FIFO */
+03834         txstatus.d32 =
+03835             dwc_read_reg32(&core_if->dev_if->in_ep_regs[ep->num]->dtxfsts);
+03836         DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", ep->num, txstatus.d32);
+03837 
+03838         while (txstatus.b.txfspcavail > dwords &&
+03839                ep->xfer_count < ep->xfer_len && ep->xfer_len != 0) {
+03840                 /* Write the FIFO */
+03841                 dwc_otg_ep_write_packet(core_if, ep, 0);
+03842 
+03843                 len = ep->xfer_len - ep->xfer_count;
+03844                 if (len > ep->maxpacket) {
+03845                         len = ep->maxpacket;
+03846                 }
+03847 
+03848                 dwords = (len + 3) / 4;
+03849                 txstatus.d32 =
+03850                     dwc_read_reg32(&core_if->dev_if->in_ep_regs[ep->num]->
+03851                                    dtxfsts);
+03852                 DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", ep->num,
+03853                             txstatus.d32);
+03854         }
+03855 }
+03856 
+03864 void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if,
+03865                                        dwc_ep_t * ep)
+03866 {
+03867         deptsiz_data_t deptsiz = {.d32 = 0 };
+03868         depctl_data_t depctl = {.d32 = 0 };
+03869         dsts_data_t dsts = {.d32 = 0 };
+03870         volatile uint32_t *addr;
+03871 
+03872         if (ep->is_in) {
+03873                 addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
+03874         } else {
+03875                 addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
+03876         }
+03877 
+03878         ep->xfer_len = ep->data_per_frame;
+03879         ep->xfer_count = 0;
+03880         ep->xfer_buff = ep->cur_pkt_addr;
+03881         ep->dma_addr = ep->cur_pkt_dma_addr;
+03882 
+03883         if (ep->is_in) {
+03884                 /* Program the transfer size and packet count
+03885                  *      as follows: xfersize = N * maxpacket +
+03886                  *      short_packet pktcnt = N + (short_packet
+03887                  *      exist ? 1 : 0)  
+03888                  */
+03889                 deptsiz.b.xfersize = ep->xfer_len;
+03890                 deptsiz.b.pktcnt =
+03891                     (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
+03892                 deptsiz.b.mc = deptsiz.b.pktcnt;
+03893                 dwc_write_reg32(&core_if->dev_if->in_ep_regs[ep->num]->dieptsiz,
+03894                                 deptsiz.d32);
+03895 
+03896                 /* Write the DMA register */
+03897                 if (core_if->dma_enable) {
+03898                         dwc_write_reg32(&
+03899                                         (core_if->dev_if->in_ep_regs[ep->num]->
+03900                                          diepdma), (uint32_t) ep->dma_addr);
+03901                 }
+03902         } else {
+03903                 deptsiz.b.pktcnt =
+03904                     (ep->xfer_len + (ep->maxpacket - 1)) / ep->maxpacket;
+03905                 deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
+03906 
+03907                 dwc_write_reg32(&core_if->dev_if->out_ep_regs[ep->num]->
+03908                                 doeptsiz, deptsiz.d32);
+03909 
+03910                 if (core_if->dma_enable) {
+03911                         dwc_write_reg32(&
+03912                                         (core_if->dev_if->out_ep_regs[ep->num]->
+03913                                          doepdma), (uint32_t) ep->dma_addr);
+03914                 }
+03915         }
+03916 
+03919         depctl.d32 = 0;
+03920         if (ep->bInterval == 1) {
+03921                 dsts.d32 =
+03922                     dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
+03923                 ep->next_frame = dsts.b.soffn + ep->bInterval;
+03924 
+03925                 if (ep->next_frame & 0x1) {
+03926                         depctl.b.setd1pid = 1;
+03927                 } else {
+03928                         depctl.b.setd0pid = 1;
+03929                 }
+03930         } else {
+03931                 ep->next_frame += ep->bInterval;
+03932 
+03933                 if (ep->next_frame & 0x1) {
+03934                         depctl.b.setd1pid = 1;
+03935                 } else {
+03936                         depctl.b.setd0pid = 1;
+03937                 }
+03938         }
+03939         depctl.b.epena = 1;
+03940         depctl.b.cnak = 1;
+03941 
+03942         dwc_modify_reg32(addr, 0, depctl.d32);
+03943         depctl.d32 = dwc_read_reg32(addr);
+03944 
+03945         if (ep->is_in && core_if->dma_enable == 0) {
+03946                 write_isoc_frame_data(core_if, ep);
+03947         }
+03948 
+03949 }
+03950 #endif                          /* DWC_EN_ISOC */
+03951 
+03952 static void dwc_otg_set_uninitialized(int32_t * p, int size)
+03953 {
+03954         int i;
+03955         for (i = 0; i < size; i++) {
+03956                 p[i] = -1;
+03957         }
+03958 }
+03959 
+03960 static int dwc_otg_param_initialized(int32_t val)
+03961 {
+03962         return val != -1;
+03963 }
+03964 
+03965 static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if)
+03966 {
+03967         int i;
+03968         core_if->core_params = DWC_ALLOC(sizeof(*core_if->core_params));
+03969         if (!core_if->core_params) {
+03970                 return -DWC_E_NO_MEMORY;
+03971         }
+03972         dwc_otg_set_uninitialized((int32_t *) core_if->core_params,
+03973                                   sizeof(*core_if->core_params) /
+03974                                   sizeof(int32_t));
+03975         DWC_PRINTF("Setting default values for core params\n");
+03976         dwc_otg_set_param_otg_cap(core_if, dwc_param_otg_cap_default);
+03977         dwc_otg_set_param_dma_enable(core_if, dwc_param_dma_enable_default);
+03978         dwc_otg_set_param_dma_desc_enable(core_if,
+03979                                           dwc_param_dma_desc_enable_default);
+03980         dwc_otg_set_param_opt(core_if, dwc_param_opt_default);
+03981         dwc_otg_set_param_dma_burst_size(core_if,
+03982                                          dwc_param_dma_burst_size_default);
+03983         dwc_otg_set_param_host_support_fs_ls_low_power(core_if,
+03984                                                        dwc_param_host_support_fs_ls_low_power_default);
+03985         dwc_otg_set_param_enable_dynamic_fifo(core_if,
+03986                                               dwc_param_enable_dynamic_fifo_default);
+03987         dwc_otg_set_param_data_fifo_size(core_if,
+03988                                          dwc_param_data_fifo_size_default);
+03989         dwc_otg_set_param_dev_rx_fifo_size(core_if,
+03990                                            dwc_param_dev_rx_fifo_size_default);
+03991         dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if,
+03992                                                   dwc_param_dev_nperio_tx_fifo_size_default);
+03993         dwc_otg_set_param_host_rx_fifo_size(core_if,
+03994                                             dwc_param_host_rx_fifo_size_default);
+03995         dwc_otg_set_param_host_nperio_tx_fifo_size(core_if,
+03996                                                    dwc_param_host_nperio_tx_fifo_size_default);
+03997         dwc_otg_set_param_host_perio_tx_fifo_size(core_if,
+03998                                                   dwc_param_host_perio_tx_fifo_size_default);
+03999         dwc_otg_set_param_max_transfer_size(core_if,
+04000                                             dwc_param_max_transfer_size_default);
+04001         dwc_otg_set_param_max_packet_count(core_if,
+04002                                            dwc_param_max_packet_count_default);
+04003         dwc_otg_set_param_host_channels(core_if,
+04004                                         dwc_param_host_channels_default);
+04005         dwc_otg_set_param_dev_endpoints(core_if,
+04006                                         dwc_param_dev_endpoints_default);
+04007         dwc_otg_set_param_phy_type(core_if, dwc_param_phy_type_default);
+04008         dwc_otg_set_param_speed(core_if, dwc_param_speed_default);
+04009         dwc_otg_set_param_host_ls_low_power_phy_clk(core_if,
+04010                                                     dwc_param_host_ls_low_power_phy_clk_default);
+04011         dwc_otg_set_param_phy_ulpi_ddr(core_if, dwc_param_phy_ulpi_ddr_default);
+04012         dwc_otg_set_param_phy_ulpi_ext_vbus(core_if,
+04013                                             dwc_param_phy_ulpi_ext_vbus_default);
+04014         dwc_otg_set_param_phy_utmi_width(core_if,
+04015                                          dwc_param_phy_utmi_width_default);
+04016         dwc_otg_set_param_ts_dline(core_if, dwc_param_ts_dline_default);
+04017         dwc_otg_set_param_i2c_enable(core_if, dwc_param_i2c_enable_default);
+04018         dwc_otg_set_param_ulpi_fs_ls(core_if, dwc_param_ulpi_fs_ls_default);
+04019         dwc_otg_set_param_en_multiple_tx_fifo(core_if,
+04020                                               dwc_param_en_multiple_tx_fifo_default);
+04021         for (i = 0; i < 15; i++) {
+04022                 dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
+04023                                                          dwc_param_dev_perio_tx_fifo_size_default,
+04024                                                          i);
+04025         }
+04026 
+04027         for (i = 0; i < 15; i++) {
+04028                 dwc_otg_set_param_dev_tx_fifo_size(core_if,
+04029                                                    dwc_param_dev_tx_fifo_size_default,
+04030                                                    i);
+04031         }
+04032         dwc_otg_set_param_thr_ctl(core_if, dwc_param_thr_ctl_default);
+04033         dwc_otg_set_param_mpi_enable(core_if, dwc_param_mpi_enable_default);
+04034         dwc_otg_set_param_pti_enable(core_if, dwc_param_pti_enable_default);
+04035         dwc_otg_set_param_lpm_enable(core_if, dwc_param_lpm_enable_default);
+04036         dwc_otg_set_param_ic_usb_cap(core_if, dwc_param_ic_usb_cap_default);
+04037         dwc_otg_set_param_tx_thr_length(core_if,
+04038                                         dwc_param_tx_thr_length_default);
+04039         dwc_otg_set_param_rx_thr_length(core_if,
+04040                                         dwc_param_rx_thr_length_default);
+04041         dwc_otg_set_param_ahb_thr_ratio(core_if, dwc_param_ahb_thr_ratio_default);
+04042         return 0;
+04043 }
+04044 
+04045 uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if)
+04046 {
+04047         return core_if->dma_enable;
+04048 }
+04049 
+04050 /* Checks if the parameter is outside of its valid range of values */
+04051 #define DWC_OTG_PARAM_TEST(_param_, _low_, _high_) \
+04052                 (((_param_) < (_low_)) || \
+04053                 ((_param_) > (_high_)))
+04054 
+04055 /* Parameter access functions */
+04056 int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val)
+04057 {
+04058         int valid;
+04059         int retval = 0;
+04060         if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
+04061                 DWC_WARN("Wrong value for otg_cap parameter\n");
+04062                 DWC_WARN("otg_cap parameter must be 0,1 or 2\n");
+04063                 retval = -DWC_E_INVALID;
+04064                 goto out;
+04065         }
+04066 
+04067         valid = 1;
+04068         switch (val) {
+04069         case DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE:
+04070                 if (core_if->hwcfg2.b.op_mode !=
+04071                     DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
+04072                         valid = 0;
+04073                 break;
+04074         case DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE:
+04075                 if ((core_if->hwcfg2.b.op_mode !=
+04076                      DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
+04077                     && (core_if->hwcfg2.b.op_mode !=
+04078                         DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
+04079                     && (core_if->hwcfg2.b.op_mode !=
+04080                         DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
+04081                     && (core_if->hwcfg2.b.op_mode !=
+04082                       DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) {
+04083                         valid = 0;
+04084                 }
+04085                 break;
+04086         case DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE:
+04087                 /* always valid */
+04088                 break;
+04089         }
+04090         if (!valid) {
+04091                 if (dwc_otg_param_initialized(core_if->core_params->otg_cap)) {
+04092                         DWC_ERROR
+04093                             ("%d invalid for otg_cap paremter. Check HW configuration.\n",
+04094                              val);
+04095                 }
+04096                 val =
+04097                     (((core_if->hwcfg2.b.op_mode ==
+04098                        DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
+04099                       || (core_if->hwcfg2.b.op_mode ==
+04100                           DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
+04101                       || (core_if->hwcfg2.b.op_mode ==
+04102                           DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
+04103                       || (core_if->hwcfg2.b.op_mode ==
+04104                           DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) ?
+04105                      DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE :
+04106                      DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
+04107                 retval = -DWC_E_INVALID;
+04108         }
+04109 
+04110         core_if->core_params->otg_cap = val;
+04111       out:
+04112         return retval;
+04113 }
+04114 
+04115 int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if)
+04116 {
+04117         return core_if->core_params->otg_cap;
+04118 }
+04119 
+04120 int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val)
+04121 {
+04122         if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+04123                 DWC_WARN("Wrong value for opt parameter\n");
+04124                 return -DWC_E_INVALID;
+04125         }
+04126         core_if->core_params->opt = val;
+04127         return 0;
+04128 }
+04129 
+04130 int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if)
+04131 {
+04132         return core_if->core_params->opt;
+04133 }
+04134 
+04135 int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if, int32_t val)
+04136 {
+04137         int retval = 0;
+04138         if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+04139                 DWC_WARN("Wrong value for dma enable\n");
+04140                 return -DWC_E_INVALID;
+04141         }
+04142 
+04143         if ((val == 1) && (core_if->hwcfg2.b.architecture == 0)) {
+04144                 if (dwc_otg_param_initialized(core_if->core_params->dma_enable)) {
+04145                         DWC_ERROR
+04146                             ("%d invalid for dma_enable paremter. Check HW configuration.\n",
+04147                              val);
+04148                 }
+04149                 val = 0;
+04150                 retval = -DWC_E_INVALID;
+04151         }
+04152 
+04153         core_if->core_params->dma_enable = val;
+04154         if (val == 0) {
+04155                 dwc_otg_set_param_dma_desc_enable(core_if, 0);
+04156         }
+04157         return retval;
+04158 }
+04159 
+04160 int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if)
+04161 {
+04162         return core_if->core_params->dma_enable;
+04163 }
+04164 
+04165 int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if, int32_t val)
+04166 {
+04167         int retval = 0;
+04168         if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+04169                 DWC_WARN("Wrong value for dma_enable\n");
+04170                 DWC_WARN("dma_desc_enable must be 0 or 1\n");
+04171                 return -DWC_E_INVALID;
+04172         }
+04173 
+04174         if ((val == 1)
+04175             && ((dwc_otg_get_param_dma_enable(core_if) == 0)
+04176                 || (core_if->hwcfg4.b.desc_dma == 0))) {
+04177                 if (dwc_otg_param_initialized
+04178                     (core_if->core_params->dma_desc_enable)) {
+04179                         DWC_ERROR
+04180                             ("%d invalid for dma_desc_enable paremter. Check HW configuration.\n",
+04181                              val);
+04182                 }
+04183                 val = 0;
+04184                 retval = -DWC_E_INVALID;
+04185         }
+04186         core_if->core_params->dma_desc_enable = val;
+04187         return retval;
+04188 }
+04189 
+04190 int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if)
+04191 {
+04192         return core_if->core_params->dma_desc_enable;
+04193 }
+04194 
+04195 int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t * core_if,
+04196                                                    int32_t val)
+04197 {
+04198         if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+04199                 DWC_WARN("Wrong value for host_support_fs_low_power\n");
+04200                 DWC_WARN("host_support_fs_low_power must be 0 or 1\n");
+04201                 return -DWC_E_INVALID;
+04202         }
+04203         core_if->core_params->host_support_fs_ls_low_power = val;
+04204         return 0;
+04205 }
+04206 
+04207 int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
+04208                                                        core_if)
+04209 {
+04210         return core_if->core_params->host_support_fs_ls_low_power;
+04211 }
+04212 
+04213 int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
+04214                                           int32_t val)
+04215 {
+04216         int retval = 0;
+04217         if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+04218                 DWC_WARN("Wrong value for enable_dynamic_fifo\n");
+04219                 DWC_WARN("enable_dynamic_fifo must be 0 or 1\n");
+04220                 return -DWC_E_INVALID;
+04221         }
+04222 
+04223         if ((val == 1) && (core_if->hwcfg2.b.dynamic_fifo == 0)) {
+04224                 if (dwc_otg_param_initialized
+04225                     (core_if->core_params->enable_dynamic_fifo)) {
+04226                         DWC_ERROR
+04227                             ("%d invalid for enable_dynamic_fifo paremter. Check HW configuration.\n",
+04228                              val);
+04229                 }
+04230                 val = 0;
+04231                 retval = -DWC_E_INVALID;
+04232         }
+04233         core_if->core_params->enable_dynamic_fifo = val;
+04234         return retval;
+04235 }
+04236 
+04237 int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if)
+04238 {
+04239         return core_if->core_params->enable_dynamic_fifo;
+04240 }
+04241 
+04242 int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if, int32_t val)
+04243 {
+04244         int retval = 0;
+04245         if (DWC_OTG_PARAM_TEST(val, 32, 32768)) {
+04246                 DWC_WARN("Wrong value for data_fifo_size\n");
+04247                 DWC_WARN("data_fifo_size must be 32-32768\n");
+04248                 return -DWC_E_INVALID;
+04249         }
+04250 
+04251         if (val > core_if->hwcfg3.b.dfifo_depth) {
+04252                 if (dwc_otg_param_initialized
+04253                     (core_if->core_params->data_fifo_size)) {
+04254                         DWC_ERROR
+04255                             ("%d invalid for data_fifo_size parameter. Check HW configuration.\n",
+04256                              val);
+04257                 }
+04258                 val = core_if->hwcfg3.b.dfifo_depth;
+04259                 retval = -DWC_E_INVALID;
+04260         }
+04261 
+04262         core_if->core_params->data_fifo_size = val;
+04263         return retval;
+04264 }
+04265 
+04266 int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if)
+04267 {
+04268         return core_if->core_params->data_fifo_size;
+04269 }
+04270 
+04271 int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val)
+04272 {
+04273         int retval = 0;
+04274         if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
+04275                 DWC_WARN("Wrong value for dev_rx_fifo_size\n");
+04276                 DWC_WARN("dev_rx_fifo_size must be 16-32768\n");
+04277                 return -DWC_E_INVALID;
+04278         }
+04279 
+04280         if (val > dwc_read_reg32(&core_if->core_global_regs->grxfsiz)) {
+04281                 if(dwc_otg_param_initialized(core_if->core_params->dev_rx_fifo_size)) {
+04282                 DWC_WARN("%d invalid for dev_rx_fifo_size parameter\n", val);
+04283                 }
+04284                 val = dwc_read_reg32(&core_if->core_global_regs->grxfsiz);
+04285                 retval = -DWC_E_INVALID;
+04286         }
+04287 
+04288         core_if->core_params->dev_rx_fifo_size = val;
+04289         return retval;
+04290 }
+04291 
+04292 int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if)
+04293 {
+04294         return core_if->core_params->dev_rx_fifo_size;
+04295 }
+04296 
+04297 int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if,
+04298                                               int32_t val)
+04299 {
+04300         int retval = 0;
+04301 
+04302         if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
+04303                 DWC_WARN("Wrong value for dev_nperio_tx_fifo\n");
+04304                 DWC_WARN("dev_nperio_tx_fifo must be 16-32768\n");
+04305                 return -DWC_E_INVALID;
+04306         }
+04307 
+04308         if (val > (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)) {
+04309                 if (dwc_otg_param_initialized
+04310                     (core_if->core_params->dev_nperio_tx_fifo_size)) {
+04311                         DWC_ERROR
+04312                             ("%d invalid for dev_nperio_tx_fifo_size. Check HW configuration.\n",
+04313                              val);
+04314                 }
+04315                 val =
+04316                     (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >>
+04317                      16);
+04318                 retval = -DWC_E_INVALID;
+04319         }
+04320 
+04321         core_if->core_params->dev_nperio_tx_fifo_size = val;
+04322         return retval;
+04323 }
+04324 
+04325 int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if)
+04326 {
+04327         return core_if->core_params->dev_nperio_tx_fifo_size;
+04328 }
+04329 
+04330 int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
+04331                                         int32_t val)
+04332 {
+04333         int retval = 0;
+04334 
+04335         if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
+04336                 DWC_WARN("Wrong value for host_rx_fifo_size\n");
+04337                 DWC_WARN("host_rx_fifo_size must be 16-32768\n");
+04338                 return -DWC_E_INVALID;
+04339         }
+04340 
+04341         if (val > dwc_read_reg32(&core_if->core_global_regs->grxfsiz)) {
+04342                 if (dwc_otg_param_initialized
+04343                     (core_if->core_params->host_rx_fifo_size)) {
+04344                         DWC_ERROR
+04345                             ("%d invalid for host_rx_fifo_size. Check HW configuration.\n",
+04346                              val);
+04347                 }
+04348                 val = dwc_read_reg32(&core_if->core_global_regs->grxfsiz);
+04349                 retval = -DWC_E_INVALID;
+04350         }
+04351 
+04352         core_if->core_params->host_rx_fifo_size = val;
+04353         return retval;
+04354 
+04355 }
+04356 
+04357 int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if)
+04358 {
+04359         return core_if->core_params->host_rx_fifo_size;
+04360 }
+04361 
+04362 int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if,
+04363                                                int32_t val)
+04364 {
+04365         int retval = 0;
+04366 
+04367         if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
+04368                 DWC_WARN("Wrong value for host_nperio_tx_fifo_size\n");
+04369                 DWC_WARN("host_nperio_tx_fifo_size must be 16-32768\n");
+04370                 return -DWC_E_INVALID;
+04371         }
+04372 
+04373         if (val > (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)) {
+04374                 if (dwc_otg_param_initialized
+04375                     (core_if->core_params->host_nperio_tx_fifo_size)) {
+04376                         DWC_ERROR
+04377                             ("%d invalid for host_nperio_tx_fifo_size. Check HW configuration.\n",
+04378                              val);
+04379                 }
+04380                 val =
+04381                     (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >>
+04382                      16);
+04383                 retval = -DWC_E_INVALID;
+04384         }
+04385 
+04386         core_if->core_params->host_nperio_tx_fifo_size = val;
+04387         return retval;
+04388 }
+04389 
+04390 int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if)
+04391 {
+04392         return core_if->core_params->host_nperio_tx_fifo_size;
+04393 }
+04394 
+04395 int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
+04396                                               int32_t val)
+04397 {
+04398         int retval = 0;
+04399         if (DWC_OTG_PARAM_TEST(val, 16, 32768)) {
+04400                 DWC_WARN("Wrong value for host_perio_tx_fifo_size\n");
+04401                 DWC_WARN("host_perio_tx_fifo_size must be 16-32768\n");
+04402                 return -DWC_E_INVALID;
+04403         }
+04404 
+04405         if (val >
+04406             ((dwc_read_reg32(&core_if->core_global_regs->hptxfsiz) >> 16))) {
+04407                 if (dwc_otg_param_initialized
+04408                     (core_if->core_params->host_perio_tx_fifo_size)) {
+04409                         DWC_ERROR
+04410                             ("%d invalid for host_perio_tx_fifo_size. Check HW configuration.\n",
+04411                              val);
+04412                 }
+04413                 val =
+04414                     (dwc_read_reg32(&core_if->core_global_regs->hptxfsiz) >>
+04415                      16);
+04416                 retval = -DWC_E_INVALID;
+04417         }
+04418 
+04419         core_if->core_params->host_perio_tx_fifo_size = val;
+04420         return retval;
+04421 }
+04422 
+04423 int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if)
+04424 {
+04425         return core_if->core_params->host_perio_tx_fifo_size;
+04426 }
+04427 
+04428 int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
+04429                                         int32_t val)
+04430 {
+04431         int retval = 0;
+04432 
+04433         if (DWC_OTG_PARAM_TEST(val, 2047, 524288)) {
+04434                 DWC_WARN("Wrong value for max_transfer_size\n");
+04435                 DWC_WARN("max_transfer_size must be 2047-524288\n");
+04436                 return -DWC_E_INVALID;
+04437         }
+04438 
+04439         if (val >= (1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11))) {
+04440                 if (dwc_otg_param_initialized
+04441                     (core_if->core_params->max_transfer_size)) {
+04442                         DWC_ERROR
+04443                             ("%d invalid for max_transfer_size. Check HW configuration.\n",
+04444                              val);
+04445                 }
+04446                 val =
+04447                     ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 11)) -
+04448                      1);
+04449                 retval = -DWC_E_INVALID;
+04450         }
+04451 
+04452         core_if->core_params->max_transfer_size = val;
+04453         return retval;
+04454 }
+04455 
+04456 int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if)
+04457 {
+04458         return core_if->core_params->max_transfer_size;
+04459 }
+04460 
+04461 int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if, int32_t val)
+04462 {
+04463         int retval = 0;
+04464 
+04465         if (DWC_OTG_PARAM_TEST(val, 15, 511)) {
+04466                 DWC_WARN("Wrong value for max_packet_count\n");
+04467                 DWC_WARN("max_packet_count must be 15-511\n");
+04468                 return -DWC_E_INVALID;
+04469         }
+04470 
+04471         if (val > (1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4))) {
+04472                 if (dwc_otg_param_initialized
+04473                     (core_if->core_params->max_packet_count)) {
+04474                         DWC_ERROR
+04475                             ("%d invalid for max_packet_count. Check HW configuration.\n",
+04476                              val);
+04477                 }
+04478                 val =
+04479                     ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1);
+04480                 retval = -DWC_E_INVALID;
+04481         }
+04482 
+04483         core_if->core_params->max_packet_count = val;
+04484         return retval;
+04485 }
+04486 
+04487 int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if)
+04488 {
+04489         return core_if->core_params->max_packet_count;
+04490 }
+04491 
+04492 int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if, int32_t val)
+04493 {
+04494         int retval = 0;
+04495 
+04496         if (DWC_OTG_PARAM_TEST(val, 1, 16)) {
+04497                 DWC_WARN("Wrong value for host_channels\n");
+04498                 DWC_WARN("host_channels must be 1-16\n");
+04499                 return -DWC_E_INVALID;
+04500         }
+04501 
+04502         if (val > (core_if->hwcfg2.b.num_host_chan + 1)) {
+04503                 if (dwc_otg_param_initialized
+04504                     (core_if->core_params->host_channels)) {
+04505                         DWC_ERROR
+04506                             ("%d invalid for host_channels. Check HW configurations.\n",
+04507                              val);
+04508                 }
+04509                 val = (core_if->hwcfg2.b.num_host_chan + 1);
+04510                 retval = -DWC_E_INVALID;
+04511         }
+04512 
+04513         core_if->core_params->host_channels = val;
+04514         return retval;
+04515 }
+04516 
+04517 int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if)
+04518 {
+04519         return core_if->core_params->host_channels;
+04520 }
+04521 
+04522 int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if, int32_t val)
+04523 {
+04524         int retval = 0;
+04525 
+04526         if (DWC_OTG_PARAM_TEST(val, 1, 15)) {
+04527                 DWC_WARN("Wrong value for dev_endpoints\n");
+04528                 DWC_WARN("dev_endpoints must be 1-15\n");
+04529                 return -DWC_E_INVALID;
+04530         }
+04531 
+04532         if (val > (core_if->hwcfg2.b.num_dev_ep)) {
+04533                 if (dwc_otg_param_initialized
+04534                     (core_if->core_params->dev_endpoints)) {
+04535                         DWC_ERROR
+04536                             ("%d invalid for dev_endpoints. Check HW configurations.\n",
+04537                              val);
+04538                 }
+04539                 val = core_if->hwcfg2.b.num_dev_ep;
+04540                 retval = -DWC_E_INVALID;
+04541         }
+04542 
+04543         core_if->core_params->dev_endpoints = val;
+04544         return retval;
+04545 }
+04546 
+04547 int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if)
+04548 {
+04549         return core_if->core_params->dev_endpoints;
+04550 }
+04551 
+04552 int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val)
+04553 {
+04554         int retval = 0;
+04555         int valid = 0;
+04556 
+04557         if (DWC_OTG_PARAM_TEST(val, 0, 2)) {
+04558                 DWC_WARN("Wrong value for phy_type\n");
+04559                 DWC_WARN("phy_type must be 0,1 or 2\n");
+04560                 return -DWC_E_INVALID;
+04561         }
+04562 #ifndef NO_FS_PHY_HW_CHECKS
+04563         if ((val == DWC_PHY_TYPE_PARAM_UTMI) &&
+04564             ((core_if->hwcfg2.b.hs_phy_type == 1) ||
+04565              (core_if->hwcfg2.b.hs_phy_type == 3))) {
+04566                 valid = 1;
+04567         } else if ((val == DWC_PHY_TYPE_PARAM_ULPI) &&
+04568                    ((core_if->hwcfg2.b.hs_phy_type == 2) ||
+04569                     (core_if->hwcfg2.b.hs_phy_type == 3))) {
+04570                 valid = 1;
+04571         } else if ((val == DWC_PHY_TYPE_PARAM_FS) &&
+04572                    (core_if->hwcfg2.b.fs_phy_type == 1)) {
+04573                 valid = 1;
+04574         }
+04575         if (!valid) {
+04576                 if (dwc_otg_param_initialized(core_if->core_params->phy_type)) {
+04577                         DWC_ERROR
+04578                             ("%d invalid for phy_type. Check HW configurations.\n",
+04579                              val);
+04580                 }
+04581                 if (core_if->hwcfg2.b.hs_phy_type) {
+04582                         if ((core_if->hwcfg2.b.hs_phy_type == 3) ||
+04583                             (core_if->hwcfg2.b.hs_phy_type == 1)) {
+04584                                 val = DWC_PHY_TYPE_PARAM_UTMI;
+04585                         } else {
+04586                                 val = DWC_PHY_TYPE_PARAM_ULPI;
+04587                         }
+04588                 }
+04589                 retval = -DWC_E_INVALID;
+04590         }
+04591 #endif
+04592         core_if->core_params->phy_type = val;
+04593         return retval;
+04594 }
+04595 
+04596 int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if)
+04597 {
+04598         return core_if->core_params->phy_type;
+04599 }
+04600 
+04601 int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val)
+04602 {
+04603         int retval = 0;
+04604         if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+04605                 DWC_WARN("Wrong value for speed parameter\n");
+04606                 DWC_WARN("max_speed parameter must be 0 or 1\n");
+04607                 return -DWC_E_INVALID;
+04608         }
+04609         if ((val == 0)
+04610             && dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS) {
+04611                 if (dwc_otg_param_initialized(core_if->core_params->speed)) {
+04612                         DWC_ERROR
+04613                             ("%d invalid for speed paremter. Check HW configuration.\n",
+04614                              val);
+04615                 }
+04616                 val =
+04617                     (dwc_otg_get_param_phy_type(core_if) ==
+04618                      DWC_PHY_TYPE_PARAM_FS ? 1 : 0);
+04619                 retval = -DWC_E_INVALID;
+04620         }
+04621         core_if->core_params->speed = val;
+04622         return retval;
+04623 }
+04624 
+04625 int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if)
+04626 {
+04627         return core_if->core_params->speed;
+04628 }
+04629 
+04630 int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if,
+04631                                                 int32_t val)
+04632 {
+04633         int retval = 0;
+04634 
+04635         if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+04636                 DWC_WARN
+04637                     ("Wrong value for host_ls_low_power_phy_clk parameter\n");
+04638                 DWC_WARN("host_ls_low_power_phy_clk must be 0 or 1\n");
+04639                 return -DWC_E_INVALID;
+04640         }
+04641 
+04642         if ((val == DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ)
+04643             && (dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS)) {
+04644                 if(dwc_otg_param_initialized(core_if->core_params->host_ls_low_power_phy_clk)) {
+04645                         DWC_ERROR("%d invalid for host_ls_low_power_phy_clk. Check HW configuration.\n",
+04646                      val);
+04647                 }
+04648                 val =
+04649                     (dwc_otg_get_param_phy_type(core_if) ==
+04650                      DWC_PHY_TYPE_PARAM_FS) ?
+04651                     DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ :
+04652                     DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ;
+04653                 retval = -DWC_E_INVALID;
+04654         }
+04655 
+04656         core_if->core_params->host_ls_low_power_phy_clk = val;
+04657         return retval;
+04658 }
+04659 
+04660 int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if)
+04661 {
+04662         return core_if->core_params->host_ls_low_power_phy_clk;
+04663 }
+04664 
+04665 int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if, int32_t val)
+04666 {
+04667         if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+04668                 DWC_WARN("Wrong value for phy_ulpi_ddr\n");
+04669                 DWC_WARN("phy_upli_ddr must be 0 or 1\n");
+04670                 return -DWC_E_INVALID;
+04671         }
+04672 
+04673         core_if->core_params->phy_ulpi_ddr = val;
+04674         return 0;
+04675 }
+04676 
+04677 int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if)
+04678 {
+04679         return core_if->core_params->phy_ulpi_ddr;
+04680 }
+04681 
+04682 int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
+04683                                         int32_t val)
+04684 {
+04685         if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+04686                 DWC_WARN("Wrong valaue for phy_ulpi_ext_vbus\n");
+04687                 DWC_WARN("phy_ulpi_ext_vbus must be 0 or 1\n");
+04688                 return -DWC_E_INVALID;
+04689         }
+04690 
+04691         core_if->core_params->phy_ulpi_ext_vbus = val;
+04692         return 0;
+04693 }
+04694 
+04695 int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if)
+04696 {
+04697         return core_if->core_params->phy_ulpi_ext_vbus;
+04698 }
+04699 
+04700 int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if, int32_t val)
+04701 {
+04702         if (DWC_OTG_PARAM_TEST(val, 8, 8) && DWC_OTG_PARAM_TEST(val, 16, 16)) {
+04703                 DWC_WARN("Wrong valaue for phy_utmi_width\n");
+04704                 DWC_WARN("phy_utmi_width must be 8 or 16\n");
+04705                 return -DWC_E_INVALID;
+04706         }
+04707 
+04708         core_if->core_params->phy_utmi_width = val;
+04709         return 0;
+04710 }
+04711 
+04712 int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if)
+04713 {
+04714         return core_if->core_params->phy_utmi_width;
+04715 }
+04716 
+04717 int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if, int32_t val)
+04718 {
+04719         if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+04720                 DWC_WARN("Wrong valaue for ulpi_fs_ls\n");
+04721                 DWC_WARN("ulpi_fs_ls must be 0 or 1\n");
+04722                 return -DWC_E_INVALID;
+04723         }
+04724 
+04725         core_if->core_params->ulpi_fs_ls = val;
+04726         return 0;
+04727 }
+04728 
+04729 int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if)
+04730 {
+04731         return core_if->core_params->ulpi_fs_ls;
+04732 }
+04733 
+04734 int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val)
+04735 {
+04736         if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+04737                 DWC_WARN("Wrong valaue for ts_dline\n");
+04738                 DWC_WARN("ts_dline must be 0 or 1\n");
+04739                 return -DWC_E_INVALID;
+04740         }
+04741 
+04742         core_if->core_params->ts_dline = val;
+04743         return 0;
+04744 }
+04745 
+04746 int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if)
+04747 {
+04748         return core_if->core_params->ts_dline;
+04749 }
+04750 
+04751 int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if, int32_t val)
+04752 {
+04753         int retval = 0;
+04754         if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+04755                 DWC_WARN("Wrong valaue for i2c_enable\n");
+04756                 DWC_WARN("i2c_enable must be 0 or 1\n");
+04757                 return -DWC_E_INVALID;
+04758         }
+04759 #ifndef NO_FS_PHY_HW_CHECK
+04760         if (val == 1 && core_if->hwcfg3.b.i2c == 0) {
+04761                 if(dwc_otg_param_initialized(core_if->core_params->i2c_enable)) {
+04762                         DWC_ERROR("%d invalid for i2c_enable. Check HW configuration.\n",
+04763                      val);
+04764                 }
+04765                 val = 0;
+04766                 retval = -DWC_E_INVALID;
+04767         }
+04768 #endif
+04769 
+04770         core_if->core_params->i2c_enable = val;
+04771         return retval;
+04772 }
+04773 
+04774 int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if)
+04775 {
+04776         return core_if->core_params->i2c_enable;
+04777 }
+04778 
+04779 int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
+04780                                              int32_t val, int fifo_num)
+04781 {
+04782         int retval = 0;
+04783 
+04784         if (DWC_OTG_PARAM_TEST(val, 4, 768)) {
+04785                 DWC_WARN("Wrong value for dev_perio_tx_fifo_size\n");
+04786                 DWC_WARN("dev_perio_tx_fifo_size must be 4-768\n");
+04787                 return -DWC_E_INVALID;
+04788         }
+04789 
+04790         if (val > (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[fifo_num]))) {
+04791                 if(dwc_otg_param_initialized(core_if->core_params->dev_perio_tx_fifo_size[fifo_num])) {
+04792                         DWC_ERROR("`%d' invalid for parameter `dev_perio_fifo_size_%d'. Check HW configuration.\n",
+04793                      val, fifo_num);
+04794                 }
+04795                 val = (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[fifo_num]));
+04796                 retval = -DWC_E_INVALID;
+04797         }
+04798 
+04799         core_if->core_params->dev_perio_tx_fifo_size[fifo_num] = val;
+04800         return retval;
+04801 }
+04802 
+04803 int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
+04804                                                  int fifo_num)
+04805 {
+04806         return core_if->core_params->dev_perio_tx_fifo_size[fifo_num];
+04807 }
+04808 
+04809 int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
+04810                                           int32_t val)
+04811 {
+04812         int retval = 0;
+04813         if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+04814                 DWC_WARN("Wrong valaue for en_multiple_tx_fifo,\n");
+04815                 DWC_WARN("en_multiple_tx_fifo must be 0 or 1\n");
+04816                 return -DWC_E_INVALID;
+04817         }
+04818 
+04819         if (val == 1 && core_if->hwcfg4.b.ded_fifo_en == 0) {
+04820                 if(dwc_otg_param_initialized(core_if->core_params->en_multiple_tx_fifo)) {
+04821                         DWC_ERROR("%d invalid for parameter en_multiple_tx_fifo. Check HW configuration.\n",
+04822                      val);
+04823                 }
+04824                 val = 0;
+04825                 retval = -DWC_E_INVALID;
+04826         }
+04827 
+04828         core_if->core_params->en_multiple_tx_fifo = val;
+04829         return retval;
+04830 }
+04831 
+04832 int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if)
+04833 {
+04834         return core_if->core_params->en_multiple_tx_fifo;
+04835 }
+04836 
+04837 int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val,
+04838                                        int fifo_num)
+04839 {
+04840         int retval = 0;
+04841 
+04842         if (DWC_OTG_PARAM_TEST(val, 4, 768)) {
+04843                 DWC_WARN("Wrong value for dev_tx_fifo_size\n");
+04844                 DWC_WARN("dev_tx_fifo_size must be 4-768\n");
+04845                 return -DWC_E_INVALID;
+04846         }
+04847 
+04848         if (val > (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[fifo_num]))) {
+04849                 if(dwc_otg_param_initialized(core_if->core_params->dev_tx_fifo_size[fifo_num])) {
+04850                         DWC_ERROR("`%d' invalid for parameter `dev_tx_fifo_size_%d'. Check HW configuration.\n",
+04851                      val, fifo_num);
+04852                 }
+04853                 val = (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[fifo_num]));
+04854                 retval = -DWC_E_INVALID;
+04855         }
+04856 
+04857         core_if->core_params->dev_tx_fifo_size[fifo_num] = val;
+04858         return retval;
+04859 }
+04860 
+04861 int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
+04862                                            int fifo_num)
+04863 {
+04864         return core_if->core_params->dev_tx_fifo_size[fifo_num];
+04865 }
+04866 
+04867 int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val)
+04868 {
+04869         int retval = 0;
+04870 
+04871         if (DWC_OTG_PARAM_TEST(val, 0, 7)) {
+04872                 DWC_WARN("Wrong value for thr_ctl\n");
+04873                 DWC_WARN("thr_ctl must be 0-7\n");
+04874                 return -DWC_E_INVALID;
+04875         }
+04876 
+04877         if ((val != 0) &&
+04878             (!dwc_otg_get_param_dma_enable(core_if) ||
+04879              !core_if->hwcfg4.b.ded_fifo_en)) {
+04880                 if(dwc_otg_param_initialized(core_if->core_params->thr_ctl)) {
+04881                         DWC_ERROR("%d invalid for parameter thr_ctl. Check HW configuration.\n",
+04882                      val);
+04883                 }
+04884                 val = 0;
+04885                 retval = -DWC_E_INVALID;
+04886         }
+04887 
+04888         core_if->core_params->thr_ctl = val;
+04889         return retval;
+04890 }
+04891 
+04892 int32_t dwc_otg_get_param_thr_ctl(dwc_otg_core_if_t * core_if)
+04893 {
+04894         return core_if->core_params->thr_ctl;
+04895 }
+04896 
+04897 int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if, int32_t val)
+04898 {
+04899         int retval = 0;
+04900 
+04901         if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+04902                 DWC_WARN("Wrong value for lpm_enable\n");
+04903                 DWC_WARN("lpm_enable must be 0 or 1\n");
+04904                 return -DWC_E_INVALID;
+04905         }
+04906 
+04907         if (val && !core_if->hwcfg3.b.otg_lpm_en) {
+04908                 if(dwc_otg_param_initialized(core_if->core_params->lpm_enable)) {
+04909                         DWC_ERROR("%d invalid for parameter lpm_enable. Check HW configuration.\n",
+04910                      val);
+04911                 }
+04912                 val = 0;
+04913                 retval = -DWC_E_INVALID;
+04914         }
+04915 
+04916         core_if->core_params->lpm_enable = val;
+04917         return retval;
+04918 }
+04919 
+04920 int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if)
+04921 {
+04922         return core_if->core_params->lpm_enable;
+04923 }
+04924 
+04925 int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if, int32_t val)
+04926 {
+04927         if (DWC_OTG_PARAM_TEST(val, 8, 128)) {
+04928                 DWC_WARN("Wrong valaue for tx_thr_length\n");
+04929                 DWC_WARN("tx_thr_length must be 8 - 128\n");
+04930                 return -DWC_E_INVALID;
+04931         }
+04932 
+04933         core_if->core_params->tx_thr_length = val;
+04934         return 0;
+04935 }
+04936 
+04937 int32_t dwc_otg_get_param_tx_thr_length(dwc_otg_core_if_t * core_if)
+04938 {
+04939         return core_if->core_params->tx_thr_length;
+04940 }
+04941 
+04942 int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if, int32_t val)
+04943 {
+04944         if (DWC_OTG_PARAM_TEST(val, 8, 128)) {
+04945                 DWC_WARN("Wrong valaue for rx_thr_length\n");
+04946                 DWC_WARN("rx_thr_length must be 8 - 128\n");
+04947                 return -DWC_E_INVALID;
+04948         }
+04949 
+04950         core_if->core_params->rx_thr_length = val;
+04951         return 0;
+04952 }
+04953 
+04954 int32_t dwc_otg_get_param_rx_thr_length(dwc_otg_core_if_t * core_if)
+04955 {
+04956         return core_if->core_params->rx_thr_length;
+04957 }
+04958 
+04959 int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if, int32_t val)
+04960 {
+04961         if (DWC_OTG_PARAM_TEST(val, 1, 1) &&
+04962             DWC_OTG_PARAM_TEST(val, 4, 4) &&
+04963             DWC_OTG_PARAM_TEST(val, 8, 8) &&
+04964             DWC_OTG_PARAM_TEST(val, 16, 16) &&
+04965             DWC_OTG_PARAM_TEST(val, 32, 32) &&
+04966             DWC_OTG_PARAM_TEST(val, 64, 64) &&
+04967             DWC_OTG_PARAM_TEST(val, 128, 128) &&
+04968             DWC_OTG_PARAM_TEST(val, 256, 256)) {
+04969                 DWC_WARN("`%d' invalid for parameter `dma_burst_size'\n", val);
+04970                 return -DWC_E_INVALID;
+04971         }
+04972         core_if->core_params->dma_burst_size = val;
+04973         return 0;
+04974 }
+04975 
+04976 int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if)
+04977 {
+04978         return core_if->core_params->dma_burst_size;
+04979 }
+04980 
+04981 int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if, int32_t val)
+04982 {
+04983         int retval = 0;
+04984         if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+04985                 DWC_WARN("`%d' invalid for parameter `pti_enable'\n", val);
+04986                 return -DWC_E_INVALID;
+04987         }
+04988         if (val && (core_if->snpsid < OTG_CORE_REV_2_72a)) {
+04989                 if (dwc_otg_param_initialized(core_if->core_params->pti_enable)) {
+04990                         DWC_ERROR("%d invalid for parameter pti_enable. Check HW configuration.\n",
+04991                              val);
+04992                 }
+04993                 retval = -DWC_E_INVALID;
+04994                 val = 0;
+04995         }
+04996         core_if->core_params->pti_enable = val;
+04997         return retval;
+04998 }
+04999 
+05000 int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if)
+05001 {
+05002         return core_if->core_params->pti_enable;
+05003 }
+05004 
+05005 int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if, int32_t val)
+05006 {
+05007         int retval = 0;
+05008         if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+05009                 DWC_WARN("`%d' invalid for parameter `mpi_enable'\n", val);
+05010                 return -DWC_E_INVALID;
+05011         }
+05012         if (val && (core_if->hwcfg2.b.multi_proc_int == 0)) {
+05013                 if (dwc_otg_param_initialized(core_if->core_params->mpi_enable)) {
+05014                         DWC_ERROR("%d invalid for parameter mpi_enable. Check HW configuration.\n",
+05015                              val);
+05016                 }
+05017                 retval = -DWC_E_INVALID;
+05018                 val = 0;
+05019         }
+05020         core_if->core_params->mpi_enable = val;
+05021         return retval;
+05022 }
+05023 
+05024 int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if)
+05025 {
+05026         return core_if->core_params->mpi_enable;
+05027 }
+05028 
+05029 int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if,
+05030                                         int32_t val)
+05031 {
+05032         int retval = 0;
+05033         if (DWC_OTG_PARAM_TEST(val, 0, 1)) {
+05034                 DWC_WARN("`%d' invalid for parameter `ic_usb_cap'\n", val);
+05035                 DWC_WARN("ic_usb_cap must be 0 or 1\n");
+05036                 return -DWC_E_INVALID;
+05037         }
+05038 
+05039         if (val && (core_if->hwcfg3.b.otg_enable_ic_usb == 0)) {
+05040                 if (dwc_otg_param_initialized(core_if->core_params->ic_usb_cap)) {
+05041                         DWC_ERROR("%d invalid for parameter ic_usb_cap. Check HW configuration.\n",
+05042                              val);
+05043                 }
+05044                 retval = -DWC_E_INVALID;
+05045                 val = 0;
+05046         }
+05047         core_if->core_params->ic_usb_cap = val;
+05048         return retval;
+05049 }
+05050 int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if)
+05051 {
+05052         return core_if->core_params->ic_usb_cap;
+05053 }
+05054 
+05055 int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if, int32_t val)
+05056 {
+05057         int retval = 0;
+05058         int valid = 1;
+05059 
+05060         if(DWC_OTG_PARAM_TEST(val, 0, 3)) {
+05061                 DWC_WARN("`%d' invalid for parameter `ahb_thr_ratio'\n", val);
+05062                 DWC_WARN("ahb_thr_ratio must be 0 - 3\n");
+05063                 return -DWC_E_INVALID;
+05064         }
+05065 
+05066         if(val && (core_if->snpsid < OTG_CORE_REV_2_81a || !dwc_otg_get_param_thr_ctl(core_if))) {
+05067                 valid = 0;
+05068         } else if(val && ((dwc_otg_get_param_tx_thr_length(core_if) / (1 << val)) < 4)) {
+05069                 valid = 0;
+05070         }
+05071         if(valid == 0) {
+05072                 if(dwc_otg_param_initialized(core_if->core_params->ahb_thr_ratio)) {
+05073                         DWC_ERROR("%d invalid for parameter ahb_thr_ratio. Chack HW configuration.\n", val);
+05074                 }
+05075                 retval = -DWC_E_INVALID;
+05076                 val = 0;
+05077         }
+05078 
+05079         core_if->core_params->ahb_thr_ratio = val;
+05080         return retval;
+05081 }
+05082 int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if)
+05083 {
+05084         return core_if->core_params->ahb_thr_ratio;
+05085 }
+05086 
+05087 
+05088 uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if)
+05089 {
+05090         gotgctl_data_t otgctl;
+05091         otgctl.d32 = dwc_read_reg32(&core_if->core_global_regs->gotgctl);
+05092         return otgctl.b.hstnegscs;
+05093 }
+05094 
+05095 uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if)
+05096 {
+05097         gotgctl_data_t otgctl;
+05098         otgctl.d32 = dwc_read_reg32(&core_if->core_global_regs->gotgctl);
+05099         return otgctl.b.sesreqscs;
+05100 }
+05101 
+05102 void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val)
+05103 {
+05104         gotgctl_data_t otgctl;
+05105         otgctl.d32 = dwc_read_reg32(&core_if->core_global_regs->gotgctl);
+05106         otgctl.b.hnpreq = val;
+05107         dwc_write_reg32(&core_if->core_global_regs->gotgctl, otgctl.d32);
+05108 }
+05109 
+05110 uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if)
+05111 {
+05112         return core_if->snpsid;
+05113 }
+05114 
+05115 uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if)
+05116 {
+05117         gotgctl_data_t otgctl;
+05118         otgctl.d32 = dwc_read_reg32(&core_if->core_global_regs->gotgctl);
+05119         return otgctl.b.currmod;
+05120 }
+05121 
+05122 uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if)
+05123 {
+05124         gusbcfg_data_t usbcfg;
+05125         usbcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->gusbcfg);
+05126         return usbcfg.b.hnpcap;
+05127 }
+05128 
+05129 void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val)
+05130 {
+05131         gusbcfg_data_t usbcfg;
+05132         usbcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->gusbcfg);
+05133         usbcfg.b.hnpcap = val;
+05134         dwc_write_reg32(&core_if->core_global_regs->gusbcfg, usbcfg.d32);
+05135 }
+05136 
+05137 uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if)
+05138 {
+05139         gusbcfg_data_t usbcfg;
+05140         usbcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->gusbcfg);
+05141         return usbcfg.b.srpcap;
+05142 }
+05143 
+05144 void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val)
+05145 {
+05146         gusbcfg_data_t usbcfg;
+05147         usbcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->gusbcfg);
+05148         usbcfg.b.srpcap = val;
+05149         dwc_write_reg32(&core_if->core_global_regs->gusbcfg, usbcfg.d32);
+05150 }
+05151 
+05152 uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if)
+05153 {
+05154         dcfg_data_t dcfg;
+05155         dcfg.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dcfg);
+05156         return dcfg.b.devspd;
+05157 }
+05158 
+05159 void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val)
+05160 {
+05161         dcfg_data_t dcfg;
+05162         dcfg.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dcfg);
+05163         dcfg.b.devspd = val;
+05164         dwc_write_reg32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
+05165 }
+05166 
+05167 uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if)
+05168 {
+05169         hprt0_data_t hprt0;
+05170         hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
+05171         return hprt0.b.prtconnsts;
+05172 }
+05173 
+05174 uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if)
+05175 {
+05176         dsts_data_t dsts;
+05177         dsts.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
+05178         return dsts.b.enumspd;
+05179 }
+05180 
+05181 uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if)
+05182 {
+05183         hprt0_data_t hprt0;
+05184         hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
+05185         return hprt0.b.prtpwr;
+05186 
+05187 }
+05188 
+05189 void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val)
+05190 {
+05191         hprt0_data_t hprt0;
+05192         hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
+05193         hprt0.b.prtpwr = val;
+05194         dwc_write_reg32(core_if->host_if->hprt0, val);
+05195 }
+05196 
+05197 uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if)
+05198 {
+05199         hprt0_data_t hprt0;
+05200         hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
+05201         return hprt0.b.prtsusp;
+05202 
+05203 }
+05204 
+05205 void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val)
+05206 {
+05207         hprt0_data_t hprt0;
+05208         hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
+05209         hprt0.b.prtsusp = val;
+05210         dwc_write_reg32(core_if->host_if->hprt0, val);
+05211 }
+05212 
+05213 void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val)
+05214 {
+05215         hprt0_data_t hprt0;
+05216         hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
+05217         hprt0.b.prtres = val;
+05218         dwc_write_reg32(core_if->host_if->hprt0, val);
+05219 }
+05220 
+05221 uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if)
+05222 {
+05223         dctl_data_t dctl;
+05224         dctl.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dctl);
+05225         return dctl.b.rmtwkupsig;
+05226 }
+05227 
+05228 uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if)
+05229 {
+05230         glpmcfg_data_t lpmcfg;
+05231         lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
+05232 
+05233         DWC_ASSERT(!
+05234                    ((core_if->lx_state == DWC_OTG_L1) ^ lpmcfg.b.prt_sleep_sts),
+05235                    "lx_state = %d, lmpcfg.prt_sleep_sts = %d\n",
+05236                    core_if->lx_state, lpmcfg.b.prt_sleep_sts);
+05237 
+05238         return lpmcfg.b.prt_sleep_sts;
+05239 }
+05240 
+05241 uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if)
+05242 {
+05243         glpmcfg_data_t lpmcfg;
+05244         lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
+05245         return lpmcfg.b.rem_wkup_en;
+05246 }
+05247 
+05248 uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if)
+05249 {
+05250         glpmcfg_data_t lpmcfg;
+05251         lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
+05252         return lpmcfg.b.appl_resp;
+05253 }
+05254 
+05255 void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val)
+05256 {
+05257         glpmcfg_data_t lpmcfg;
+05258         lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
+05259         lpmcfg.b.appl_resp = val;
+05260         dwc_write_reg32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
+05261 }
+05262 
+05263 uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if)
+05264 {
+05265         glpmcfg_data_t lpmcfg;
+05266         lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
+05267         return lpmcfg.b.hsic_connect;
+05268 }
+05269 
+05270 void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val)
+05271 {
+05272         glpmcfg_data_t lpmcfg;
+05273         lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
+05274         lpmcfg.b.hsic_connect = val;
+05275         dwc_write_reg32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
+05276 }
+05277 
+05278 uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if)
+05279 {
+05280         glpmcfg_data_t lpmcfg;
+05281         lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
+05282         return lpmcfg.b.inv_sel_hsic;
+05283 
+05284 }
+05285 
+05286 void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val)
+05287 {
+05288         glpmcfg_data_t lpmcfg;
+05289         lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
+05290         lpmcfg.b.inv_sel_hsic = val;
+05291         dwc_write_reg32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
+05292 }
+05293 
+05294 uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if)
+05295 {
+05296         return dwc_read_reg32(&core_if->core_global_regs->gotgctl);
+05297 }
+05298 
+05299 void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val)
+05300 {
+05301         dwc_write_reg32(&core_if->core_global_regs->gotgctl, val);
+05302 }
+05303 
+05304 uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if)
+05305 {
+05306         return dwc_read_reg32(&core_if->core_global_regs->gusbcfg);
+05307 }
+05308 
+05309 void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val)
+05310 {
+05311         dwc_write_reg32(&core_if->core_global_regs->gusbcfg, val);
+05312 }
+05313 
+05314 uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if)
+05315 {
+05316         return dwc_read_reg32(&core_if->core_global_regs->grxfsiz);
+05317 }
+05318 
+05319 void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val)
+05320 {
+05321         dwc_write_reg32(&core_if->core_global_regs->grxfsiz, val);
+05322 }
+05323 
+05324 uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if)
+05325 {
+05326         return dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz);
+05327 }
+05328 
+05329 void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val)
+05330 {
+05331         dwc_write_reg32(&core_if->core_global_regs->gnptxfsiz, val);
+05332 }
+05333 
+05334 uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if)
+05335 {
+05336         return dwc_read_reg32(&core_if->core_global_regs->gpvndctl);
+05337 }
+05338 
+05339 void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val)
+05340 {
+05341         dwc_write_reg32(&core_if->core_global_regs->gpvndctl, val);
+05342 }
+05343 
+05344 uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if)
+05345 {
+05346         return dwc_read_reg32(&core_if->core_global_regs->ggpio);
+05347 }
+05348 
+05349 void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val)
+05350 {
+05351         dwc_write_reg32(&core_if->core_global_regs->ggpio, val);
+05352 }
+05353 
+05354 uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if)
+05355 {
+05356         return dwc_read_reg32(core_if->host_if->hprt0);
+05357 
+05358 }
+05359 
+05360 void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val)
+05361 {
+05362         dwc_write_reg32(core_if->host_if->hprt0, val);
+05363 }
+05364 
+05365 uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if)
+05366 {
+05367         return dwc_read_reg32(&core_if->core_global_regs->guid);
+05368 }
+05369 
+05370 void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val)
+05371 {
+05372         dwc_write_reg32(&core_if->core_global_regs->guid, val);
+05373 }
+05374 
+05375 uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if)
+05376 {
+05377         return dwc_read_reg32(&core_if->core_global_regs->hptxfsiz);
+05378 }
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil_8c.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil_8c.html new file mode 100644 index 000000000000..38aba4b62294 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil_8c.html @@ -0,0 +1,3103 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_cil.c File Reference + + + + + + +

dwc_otg_cil.c File Reference

The Core Interface Layer provides basic services for accessing and managing the DWC_otg hardware. More... +

+#include "dwc_os.h"
+#include "dwc_otg_regs.h"
+#include "dwc_otg_cil.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Defines

#define DWC_OTG_PARAM_TEST(_param_, _low_, _high_)

Functions

+static int dwc_otg_setup_params (dwc_otg_core_if_t *core_if)
dwc_otg_core_if_tdwc_otg_cil_init (const uint32_t *reg_base_addr)
 This function is called to initialize the DWC_otg CSR data structures.
void dwc_otg_cil_remove (dwc_otg_core_if_t *core_if)
 This function frees the structures allocated by dwc_otg_cil_init().
void dwc_otg_enable_global_interrupts (dwc_otg_core_if_t *core_if)
 This function enables the controller's Global Interrupt in the AHB Config register.
void dwc_otg_disable_global_interrupts (dwc_otg_core_if_t *core_if)
 This function disables the controller's Global Interrupt in the AHB Config register.
static void dwc_otg_enable_common_interrupts (dwc_otg_core_if_t *core_if)
 This function initializes the commmon interrupts, used in both device and host modes.
+static void init_fslspclksel (dwc_otg_core_if_t *core_if)
 Initializes the FSLSPClkSel field of the HCFG register depending on the PHY type.
+static void init_devspd (dwc_otg_core_if_t *core_if)
 Initializes the DevSpd field of the DCFG register depending on the PHY type and the enumeration speed of the device.
static uint32_t calc_num_in_eps (dwc_otg_core_if_t *core_if)
 This function calculates the number of IN EPS using GHWCFG1 and GHWCFG2 registers values.
static uint32_t calc_num_out_eps (dwc_otg_core_if_t *core_if)
 This function calculates the number of OUT EPS using GHWCFG1 and GHWCFG2 registers values.
void dwc_otg_core_init (dwc_otg_core_if_t *core_if)
 This function initializes the DWC_otg controller registers and prepares the core for device mode or host mode operation.
void dwc_otg_enable_device_interrupts (dwc_otg_core_if_t *core_if)
 This function enables the Device mode interrupts.
void dwc_otg_core_dev_init (dwc_otg_core_if_t *core_if)
 This function initializes the DWC_otg controller registers for device mode.
void dwc_otg_enable_host_interrupts (dwc_otg_core_if_t *core_if)
 This function enables the Host mode interrupts.
void dwc_otg_disable_host_interrupts (dwc_otg_core_if_t *core_if)
 This function disables the Host Mode interrupts.
void dwc_otg_core_host_init (dwc_otg_core_if_t *core_if)
 This function initializes the DWC_otg controller registers for host mode.
void dwc_otg_hc_init (dwc_otg_core_if_t *core_if, dwc_hc_t *hc)
 Prepares a host channel for transferring packets to/from a specific endpoint.
void dwc_otg_hc_halt (dwc_otg_core_if_t *core_if, dwc_hc_t *hc, dwc_otg_halt_status_e halt_status)
 Attempts to halt a host channel.
void dwc_otg_hc_cleanup (dwc_otg_core_if_t *core_if, dwc_hc_t *hc)
 Clears the transfer state for a host channel.
static void hc_set_even_odd_frame (dwc_otg_core_if_t *core_if, dwc_hc_t *hc, hcchar_data_t *hcchar)
 Sets the channel property that indicates in which frame a periodic transfer should occur.
+void set_pid_isoc (dwc_hc_t *hc)
void dwc_otg_hc_start_transfer (dwc_otg_core_if_t *core_if, dwc_hc_t *hc)
 This function does the setup for a data transfer for a host channel and starts the transfer.
void dwc_otg_hc_start_transfer_ddma (dwc_otg_core_if_t *core_if, dwc_hc_t *hc)
 This function does the setup for a data transfer for a host channel and starts the transfer in Descriptor DMA mode.
int dwc_otg_hc_continue_transfer (dwc_otg_core_if_t *core_if, dwc_hc_t *hc)
 This function continues a data transfer that was started by previous call to dwc_otg_hc_start_transfer.
void dwc_otg_hc_do_ping (dwc_otg_core_if_t *core_if, dwc_hc_t *hc)
 Starts a PING transfer.
+void dwc_otg_hc_write_packet (dwc_otg_core_if_t *core_if, dwc_hc_t *hc)
uint32_t dwc_otg_get_frame_number (dwc_otg_core_if_t *core_if)
 Gets the current USB frame number.
void dwc_otg_read_setup_packet (dwc_otg_core_if_t *core_if, uint32_t *dest)
 This function reads a setup packet from the Rx FIFO into the destination buffer.
void dwc_otg_ep0_activate (dwc_otg_core_if_t *core_if, dwc_ep_t *ep)
 This function enables EP0 OUT to receive SETUP packets and configures EP0 IN for transmitting packets.
void dwc_otg_ep_activate (dwc_otg_core_if_t *core_if, dwc_ep_t *ep)
 This function activates an EP.
void dwc_otg_ep_deactivate (dwc_otg_core_if_t *core_if, dwc_ep_t *ep)
 This function deactivates an EP.
static void init_dma_desc_chain (dwc_otg_core_if_t *core_if, dwc_ep_t *ep)
 This function initializes dma descriptor chain.
void dwc_otg_ep_start_transfer (dwc_otg_core_if_t *core_if, dwc_ep_t *ep)
 This function does the setup for a data transfer for an EP and starts the transfer.
void dwc_otg_ep_start_zl_transfer (dwc_otg_core_if_t *core_if, dwc_ep_t *ep)
 This function setup a zero length transfer in Buffer DMA and Slave modes for usb requests with zero field set.
void dwc_otg_ep0_start_transfer (dwc_otg_core_if_t *core_if, dwc_ep_t *ep)
 This function does the setup for a data transfer for EP0 and starts the transfer.
void dwc_otg_ep0_continue_transfer (dwc_otg_core_if_t *core_if, dwc_ep_t *ep)
 This function continues control IN transfers started by dwc_otg_ep0_start_transfer, when the transfer does not fit in a single packet.
+static void dump_msg (const u8 *buf, unsigned int length)
void dwc_otg_ep_write_packet (dwc_otg_core_if_t *core_if, dwc_ep_t *ep, int dma)
 This function writes a packet into the Tx FIFO associated with the EP.
void dwc_otg_ep_set_stall (dwc_otg_core_if_t *core_if, dwc_ep_t *ep)
 Set the EP STALL.
void dwc_otg_ep_clear_stall (dwc_otg_core_if_t *core_if, dwc_ep_t *ep)
 Clear the EP STALL.
void dwc_otg_read_packet (dwc_otg_core_if_t *core_if, uint8_t *dest, uint16_t bytes)
 This function reads a packet from the Rx FIFO into the destination buffer.
void dwc_otg_dump_dev_registers (dwc_otg_core_if_t *core_if)
 Dump core registers and SPRAM.
void dwc_otg_dump_spram (dwc_otg_core_if_t *core_if)
 This functions reads the SPRAM and prints its content.
void dwc_otg_dump_host_registers (dwc_otg_core_if_t *core_if)
 This function reads the host registers and prints them.
void dwc_otg_dump_global_registers (dwc_otg_core_if_t *core_if)
 This function reads the core global registers and prints them.
void dwc_otg_flush_tx_fifo (dwc_otg_core_if_t *core_if, const int num)
 Flush a Tx FIFO.
void dwc_otg_flush_rx_fifo (dwc_otg_core_if_t *core_if)
 Flush Rx FIFO.
void dwc_otg_core_reset (dwc_otg_core_if_t *core_if)
 Do core a soft reset of the core.
+uint8_t dwc_otg_is_device_mode (dwc_otg_core_if_t *_core_if)
+uint8_t dwc_otg_is_host_mode (dwc_otg_core_if_t *_core_if)
void dwc_otg_cil_register_hcd_callbacks (dwc_otg_core_if_t *core_if, dwc_otg_cil_callbacks_t *cb, void *p)
 Register HCD callbacks.
void dwc_otg_cil_register_pcd_callbacks (dwc_otg_core_if_t *core_if, dwc_otg_cil_callbacks_t *cb, void *p)
 Register PCD callbacks.
void write_isoc_frame_data (dwc_otg_core_if_t *core_if, dwc_ep_t *ep)
 This function writes isoc data per 1 (micro)frame into tx fifo.
void dwc_otg_iso_ep_start_frm_transfer (dwc_otg_core_if_t *core_if, dwc_ep_t *ep)
 This function initializes a descriptor chain for Isochronous transfer.
+static void dwc_otg_set_uninitialized (int32_t *p, int size)
+static int dwc_otg_param_initialized (int32_t val)
+uint8_t dwc_otg_is_dma_enable (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_otg_cap (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies the OTG capabilities.
+int32_t dwc_otg_get_param_otg_cap (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_opt (dwc_otg_core_if_t *core_if, int32_t val)
+int32_t dwc_otg_get_param_opt (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_dma_enable (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies whether to use slave or DMA mode for accessing the data FIFOs.
+int32_t dwc_otg_get_param_dma_enable (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_dma_desc_enable (dwc_otg_core_if_t *core_if, int32_t val)
 When DMA mode is enabled specifies whether to use address DMA or DMA Descritor mode for accessing the data FIFOs in device mode.
+int32_t dwc_otg_get_param_dma_desc_enable (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_host_support_fs_ls_low_power (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies whether low power mode is supported when attached to a Full Speed or Low Speed device in host mode.
+int32_t dwc_otg_get_param_host_support_fs_ls_low_power (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_enable_dynamic_fifo (dwc_otg_core_if_t *core_if, int32_t val)
 0 - Use cC FIFO size parameters 1 - Allow dynamic FIFO sizing (default)
+int32_t dwc_otg_get_param_enable_dynamic_fifo (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_data_fifo_size (dwc_otg_core_if_t *core_if, int32_t val)
 Total number of 4-byte words in the data FIFO memory.
+int32_t dwc_otg_get_param_data_fifo_size (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_dev_rx_fifo_size (dwc_otg_core_if_t *core_if, int32_t val)
 Number of 4-byte words in the Rx FIFO in device mode when dynamic FIFO sizing is enabled.
+int32_t dwc_otg_get_param_dev_rx_fifo_size (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_dev_nperio_tx_fifo_size (dwc_otg_core_if_t *core_if, int32_t val)
 Number of 4-byte words in the non-periodic Tx FIFO in device mode when dynamic FIFO sizing is enabled.
+int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_host_rx_fifo_size (dwc_otg_core_if_t *core_if, int32_t val)
 Number of 4-byte words in the Rx FIFO in host mode when dynamic FIFO sizing is enabled.
+int32_t dwc_otg_get_param_host_rx_fifo_size (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_host_nperio_tx_fifo_size (dwc_otg_core_if_t *core_if, int32_t val)
 Number of 4-byte words in the non-periodic Tx FIFO in host mode when Dynamic FIFO sizing is enabled in the core.
+int32_t dwc_otg_get_param_host_nperio_tx_fifo_size (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_host_perio_tx_fifo_size (dwc_otg_core_if_t *core_if, int32_t val)
 Number of 4-byte words in the host periodic Tx FIFO when dynamic FIFO sizing is enabled.
+int32_t dwc_otg_get_param_host_perio_tx_fifo_size (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_max_transfer_size (dwc_otg_core_if_t *core_if, int32_t val)
 The maximum transfer size supported in bytes.
+int32_t dwc_otg_get_param_max_transfer_size (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_max_packet_count (dwc_otg_core_if_t *core_if, int32_t val)
 The maximum number of packets in a transfer.
+int32_t dwc_otg_get_param_max_packet_count (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_host_channels (dwc_otg_core_if_t *core_if, int32_t val)
 The number of host channel registers to use.
+int32_t dwc_otg_get_param_host_channels (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_dev_endpoints (dwc_otg_core_if_t *core_if, int32_t val)
 The number of endpoints in addition to EP0 available for device mode operations.
+int32_t dwc_otg_get_param_dev_endpoints (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_phy_type (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies the type of PHY interface to use.
+int32_t dwc_otg_get_param_phy_type (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_speed (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies the maximum speed of operation in host and device mode.
+int32_t dwc_otg_get_param_speed (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_host_ls_low_power_phy_clk (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies the PHY clock rate in low power mode when connected to a Low Speed device in host mode.
+int32_t dwc_otg_get_param_host_ls_low_power_phy_clk (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_phy_ulpi_ddr (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies whether the ULPI operates at double or single data rate.
+int32_t dwc_otg_get_param_phy_ulpi_ddr (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_phy_ulpi_ext_vbus (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies whether to use the internal or external supply to drive the vbus with a ULPI phy.
+int32_t dwc_otg_get_param_phy_ulpi_ext_vbus (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_phy_utmi_width (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies the UTMI+ Data Width.
+int32_t dwc_otg_get_param_phy_utmi_width (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_ulpi_fs_ls (dwc_otg_core_if_t *core_if, int32_t val)
+int32_t dwc_otg_get_param_ulpi_fs_ls (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_ts_dline (dwc_otg_core_if_t *core_if, int32_t val)
+int32_t dwc_otg_get_param_ts_dline (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_i2c_enable (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies whether to use the I2Cinterface for full speed PHY.
+int32_t dwc_otg_get_param_i2c_enable (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_dev_perio_tx_fifo_size (dwc_otg_core_if_t *core_if, int32_t val, int fifo_num)
 Number of 4-byte words in each of the periodic Tx FIFOs in device mode when dynamic FIFO sizing is enabled.
+int32_t dwc_otg_get_param_dev_perio_tx_fifo_size (dwc_otg_core_if_t *core_if, int fifo_num)
+int dwc_otg_set_param_en_multiple_tx_fifo (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies whether dedicated transmit FIFOs are enabled for non periodic IN endpoints in device mode 0 - No 1 - Yes.
+int32_t dwc_otg_get_param_en_multiple_tx_fifo (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_dev_tx_fifo_size (dwc_otg_core_if_t *core_if, int32_t val, int fifo_num)
+int32_t dwc_otg_get_param_dev_tx_fifo_size (dwc_otg_core_if_t *core_if, int fifo_num)
+int dwc_otg_set_param_thr_ctl (dwc_otg_core_if_t *core_if, int32_t val)
 Thresholding enable flag- bit 0 - enable non-ISO Tx thresholding bit 1 - enable ISO Tx thresholding bit 2 - enable Rx thresholding.
+int32_t dwc_otg_get_param_thr_ctl (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_lpm_enable (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies whether LPM (Link Power Management) support is enabled.
+int32_t dwc_otg_get_param_lpm_enable (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_tx_thr_length (dwc_otg_core_if_t *core_if, int32_t val)
 Thresholding length for Tx FIFOs in 32 bit DWORDs.
+int32_t dwc_otg_get_param_tx_thr_length (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_rx_thr_length (dwc_otg_core_if_t *core_if, int32_t val)
 Thresholding length for Rx FIFOs in 32 bit DWORDs.
+int32_t dwc_otg_get_param_rx_thr_length (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_dma_burst_size (dwc_otg_core_if_t *core_if, int32_t val)
 The DMA Burst size (applicable only for External DMA Mode).
+int32_t dwc_otg_get_param_dma_burst_size (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_pti_enable (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies whether PTI enhancement is enabled.
+int32_t dwc_otg_get_param_pti_enable (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_mpi_enable (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies whether MPI enhancement is enabled.
+int32_t dwc_otg_get_param_mpi_enable (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_ic_usb_cap (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies whether IC_USB capability is enabled.
+int32_t dwc_otg_get_param_ic_usb_cap (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_ahb_thr_ratio (dwc_otg_core_if_t *core_if, int32_t val)
+int32_t dwc_otg_get_param_ahb_thr_ratio (dwc_otg_core_if_t *core_if)
+uint32_t dwc_otg_get_hnpstatus (dwc_otg_core_if_t *core_if)
 Get host negotiation status.
+uint32_t dwc_otg_get_srpstatus (dwc_otg_core_if_t *core_if)
 Get srp status.
+void dwc_otg_set_hnpreq (dwc_otg_core_if_t *core_if, uint32_t val)
 Set hnpreq bit in the GOTGCTL register.
+uint32_t dwc_otg_get_gsnpsid (dwc_otg_core_if_t *core_if)
 Get Content of SNPSID register.
uint32_t dwc_otg_get_mode (dwc_otg_core_if_t *core_if)
 Get current mode.
+uint32_t dwc_otg_get_hnpcapable (dwc_otg_core_if_t *core_if)
 Get value of hnpcapable field in the GUSBCFG register.
+void dwc_otg_set_hnpcapable (dwc_otg_core_if_t *core_if, uint32_t val)
 Set value of hnpcapable field in the GUSBCFG register.
+uint32_t dwc_otg_get_srpcapable (dwc_otg_core_if_t *core_if)
 Get value of srpcapable field in the GUSBCFG register.
+void dwc_otg_set_srpcapable (dwc_otg_core_if_t *core_if, uint32_t val)
 Set value of srpcapable field in the GUSBCFG register.
+uint32_t dwc_otg_get_devspeed (dwc_otg_core_if_t *core_if)
 Get value of devspeed field in the DCFG register.
+void dwc_otg_set_devspeed (dwc_otg_core_if_t *core_if, uint32_t val)
 Set value of devspeed field in the DCFG register.
+uint32_t dwc_otg_get_busconnected (dwc_otg_core_if_t *core_if)
 Get the value of busconnected field from the HPRT0 register.
+uint32_t dwc_otg_get_enumspeed (dwc_otg_core_if_t *core_if)
 Gets the device enumeration Speed.
+uint32_t dwc_otg_get_prtpower (dwc_otg_core_if_t *core_if)
 Get value of prtpwr field from the HPRT0 register.
+void dwc_otg_set_prtpower (dwc_otg_core_if_t *core_if, uint32_t val)
 Set value of prtpwr field from the HPRT0 register.
+uint32_t dwc_otg_get_prtsuspend (dwc_otg_core_if_t *core_if)
 Get value of prtsusp field from the HPRT0 regsiter.
+void dwc_otg_set_prtsuspend (dwc_otg_core_if_t *core_if, uint32_t val)
 Set value of prtpwr field from the HPRT0 register.
+void dwc_otg_set_prtresume (dwc_otg_core_if_t *core_if, uint32_t val)
 Set value of prtres field from the HPRT0 register FIXME Remove?
+uint32_t dwc_otg_get_remotewakesig (dwc_otg_core_if_t *core_if)
 Get value of rmtwkupsig bit in DCTL register.
+uint32_t dwc_otg_get_lpm_portsleepstatus (dwc_otg_core_if_t *core_if)
 Get value of prt_sleep_sts field from the GLPMCFG register.
+uint32_t dwc_otg_get_lpm_remotewakeenabled (dwc_otg_core_if_t *core_if)
 Get value of rem_wkup_en field from the GLPMCFG register.
+uint32_t dwc_otg_get_lpmresponse (dwc_otg_core_if_t *core_if)
 Get value of appl_resp field from the GLPMCFG register.
+void dwc_otg_set_lpmresponse (dwc_otg_core_if_t *core_if, uint32_t val)
 Set value of appl_resp field from the GLPMCFG register.
+uint32_t dwc_otg_get_hsic_connect (dwc_otg_core_if_t *core_if)
 Get value of hsic_connect field from the GLPMCFG register.
+void dwc_otg_set_hsic_connect (dwc_otg_core_if_t *core_if, uint32_t val)
 Set value of hsic_connect field from the GLPMCFG register.
+uint32_t dwc_otg_get_inv_sel_hsic (dwc_otg_core_if_t *core_if)
 Get value of inv_sel_hsic field from the GLPMCFG register.
+void dwc_otg_set_inv_sel_hsic (dwc_otg_core_if_t *core_if, uint32_t val)
 Set value of inv_sel_hsic field from the GLPMFG register.
+uint32_t dwc_otg_get_gotgctl (dwc_otg_core_if_t *core_if)
 GOTGCTL register.
+void dwc_otg_set_gotgctl (dwc_otg_core_if_t *core_if, uint32_t val)
+uint32_t dwc_otg_get_gusbcfg (dwc_otg_core_if_t *core_if)
 GUSBCFG register.
+void dwc_otg_set_gusbcfg (dwc_otg_core_if_t *core_if, uint32_t val)
+uint32_t dwc_otg_get_grxfsiz (dwc_otg_core_if_t *core_if)
 GRXFSIZ register.
+void dwc_otg_set_grxfsiz (dwc_otg_core_if_t *core_if, uint32_t val)
+uint32_t dwc_otg_get_gnptxfsiz (dwc_otg_core_if_t *core_if)
 GNPTXFSIZ register.
+void dwc_otg_set_gnptxfsiz (dwc_otg_core_if_t *core_if, uint32_t val)
+uint32_t dwc_otg_get_gpvndctl (dwc_otg_core_if_t *core_if)
+void dwc_otg_set_gpvndctl (dwc_otg_core_if_t *core_if, uint32_t val)
+uint32_t dwc_otg_get_ggpio (dwc_otg_core_if_t *core_if)
 GGPIO register.
+void dwc_otg_set_ggpio (dwc_otg_core_if_t *core_if, uint32_t val)
+uint32_t dwc_otg_get_hprt0 (dwc_otg_core_if_t *core_if)
 HPRT0 register.
+void dwc_otg_set_hprt0 (dwc_otg_core_if_t *core_if, uint32_t val)
+uint32_t dwc_otg_get_guid (dwc_otg_core_if_t *core_if)
 GUID register.
+void dwc_otg_set_guid (dwc_otg_core_if_t *core_if, uint32_t val)
+uint32_t dwc_otg_get_hptxfsiz (dwc_otg_core_if_t *core_if)
 GHPTXFSIZE.
+


Detailed Description

+The Core Interface Layer provides basic services for accessing and managing the DWC_otg hardware. +

+These services are used by both the Host Controller Driver and the Peripheral Controller Driver.

+The CIL manages the memory map for the core so that the HCD and PCD don't have to do this separately. It also handles basic tasks like reading/writing the registers and data FIFOs in the controller. Some of the data access functions provide encapsulation of several operations required to perform a task, such as writing multiple registers to start a transfer. Finally, the CIL performs basic services that are not specific to either the host or device modes of operation. These services include management of the OTG Host Negotiation Protocol (HNP) and Session Request Protocol (SRP). A Diagnostic API is also provided to allow testing of the controller hardware.

+The Core Interface Layer has the following requirements:

    +
  • Provides basic controller operations.
  • Minimal use of OS services.
  • The OS services used will be abstracted by using inline functions or macros.
+ +

+Definition in file dwc_otg_cil.c.


Define Documentation

+ +
+
+ + + + + + + + + + + + + + + +
#define DWC_OTG_PARAM_TEST (_param_,
_low_,
_high_   ) 
+
+
+ +

+Value:

(((_param_) < (_low_)) || \
+                ((_param_) > (_high_)))
+
+

+Definition at line 4051 of file dwc_otg_cil.c. +

+

+


Function Documentation

+ +
+
+ + + + + + + + + +
dwc_otg_core_if_t* dwc_otg_cil_init (const uint32_t *  reg_base_addr  ) 
+
+
+ +

+This function is called to initialize the DWC_otg CSR data structures. +

+The register addresses in the device and host structures are initialized from the base address supplied by the caller. The calling function must make the OS calls to get the base address of the DWC_otg controller registers. The core_params argument holds the parameters that specify how the core should be configured.

+

Parameters:
+ + +
reg_base_addr Base address of DWC_otg core registers
+
+ +

+Definition at line 78 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_cil_remove (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function frees the structures allocated by dwc_otg_cil_init(). +

+

Parameters:
+ + +
core_if The core interface pointer returned from dwc_otg_cil_init().
+
+ +

+Definition at line 265 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_enable_global_interrupts (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function enables the controller's Global Interrupt in the AHB Config register. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 292 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_disable_global_interrupts (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function disables the controller's Global Interrupt in the AHB Config register. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 305 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
static void dwc_otg_enable_common_interrupts (dwc_otg_core_if_t core_if  )  [static]
+
+
+ +

+This function initializes the commmon interrupts, used in both device and host modes. +

+

Parameters:
+ + +
core_if Programming view of the DWC_otg controller
+
+ +

+Definition at line 319 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
static uint32_t calc_num_in_eps (dwc_otg_core_if_t core_if  )  [static]
+
+
+ +

+This function calculates the number of IN EPS using GHWCFG1 and GHWCFG2 registers values. +

+

Parameters:
+ + +
core_if Programming view of the DWC_otg controller
+
+ +

+Definition at line 415 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
static uint32_t calc_num_out_eps (dwc_otg_core_if_t core_if  )  [static]
+
+
+ +

+This function calculates the number of OUT EPS using GHWCFG1 and GHWCFG2 registers values. +

+

Parameters:
+ + +
core_if Programming view of the DWC_otg controller
+
+ +

+Definition at line 444 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_core_init (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function initializes the DWC_otg controller registers and prepares the core for device mode or host mode operation. +

+

Parameters:
+ + +
core_if Programming view of the DWC_otg controller
+
+ +

+Definition at line 467 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_enable_device_interrupts (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function enables the Device mode interrupts. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller
+
+ +

+

Todo:
NGS: Should this be a module parameter?
+ +

+Definition at line 772 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_core_dev_init (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function initializes the DWC_otg controller registers for device mode. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller
+
+ +

+Set Periodic Tx FIFO Mask all bits 0

+Set Tx FIFO Mask all bits 0

+

Todo:
NGS: Fix Periodic FIFO Sizing!
+

+

Todo:
Finish debug of this
+

+

Todo:
    +
  • if the condition needed to be checked or in any case all pending interrutps should be cleared?
+
+ +

+Definition at line 843 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_enable_host_interrupts (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function enables the Host mode interrupts. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller
+
+ +

+Definition at line 1130 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_disable_host_interrupts (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function disables the Host Mode interrupts. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller
+
+ +

+Definition at line 1165 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_core_host_init (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function initializes the DWC_otg controller registers for host mode. +

+This function flushes the Tx and Rx FIFOs and it flushes any entries in the request queues. Host channels are reset to ensure that they are ready for performing transfers.

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller
+
+ +

+Definition at line 1196 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hc_init (dwc_otg_core_if_t core_if,
dwc_hc_t hc 
)
+
+
+ +

+Prepares a host channel for transferring packets to/from a specific endpoint. +

+The HCCHARn register is set up with the characteristics specified in _hc. Host channel interrupts that may need to be serviced while this transfer is in progress are enabled.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller
hc Information needed to initialize the host channel
+
+ +

+Definition at line 1352 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_hc_halt (dwc_otg_core_if_t core_if,
dwc_hc_t hc,
dwc_otg_halt_status_e  halt_status 
)
+
+
+ +

+Attempts to halt a host channel. +

+This function should only be called in Slave mode or to abort a transfer in either Slave mode or DMA mode. Under normal circumstances in DMA mode, the controller halts the channel when the transfer is complete or a condition occurs that requires application intervention.

+In slave mode, checks for a free request queue entry, then sets the Channel Enable and Channel Disable bits of the Host Channel Characteristics register of the specified channel to intiate the halt. If there is no free request queue entry, sets only the Channel Disable bit of the HCCHARn register to flush requests for this channel. In the latter case, sets a flag to indicate that the host channel needs to be halted when a request queue slot is open.

+In DMA mode, always sets the Channel Enable and Channel Disable bits of the HCCHARn register. The controller ensures there is space in the request queue before submitting the halt request.

+Some time may elapse before the core flushes any posted requests for this host channel and halts. The Channel Halted interrupt handler completes the deactivation of the host channel.

+

Parameters:
+ + + + +
core_if Controller register interface.
hc Host channel to halt.
halt_status Reason for halting the channel.
+
+ +

+Definition at line 1540 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hc_cleanup (dwc_otg_core_if_t core_if,
dwc_hc_t hc 
)
+
+
+ +

+Clears the transfer state for a host channel. +

+This function is normally called after a transfer is done and the host channel is being released.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
hc Identifies the host channel to clean up.
+
+ +

+Definition at line 1667 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
static void hc_set_even_odd_frame (dwc_otg_core_if_t core_if,
dwc_hc_t hc,
hcchar_data_t hcchar 
) [inline, static]
+
+
+ +

+Sets the channel property that indicates in which frame a periodic transfer should occur. +

+This is always set to the _next_ frame. This function has no effect on non-periodic transfers.

+

Parameters:
+ + + + +
core_if Programming view of DWC_otg controller.
hc Identifies the host channel to set up and its properties.
hcchar Current value of the HCCHAR register for the specified host channel.
+
+ +

+Definition at line 1695 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hc_start_transfer (dwc_otg_core_if_t core_if,
dwc_hc_t hc 
)
+
+
+ +

+This function does the setup for a data transfer for a host channel and starts the transfer. +

+May be called in either Slave mode or DMA mode. In Slave mode, the caller must ensure that there is sufficient space in the request queue and Tx Data FIFO.

+For an OUT transfer in Slave mode, it loads a data packet into the appropriate FIFO. If necessary, additional data packets will be loaded in the Host ISR.

+For an IN transfer in Slave mode, a data packet is requested. The data packets are unloaded from the Rx FIFO in the Host ISR. If necessary, additional data packets are requested in the Host ISR.

+For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ register along with a packet count of 1 and the channel is enabled. This causes a single PING transaction to occur. Other fields in HCTSIZ are simply set to 0 since no data transfer occurs in this case.

+For a PING transfer in DMA mode, the HCTSIZ register is initialized with all the information required to perform the subsequent data transfer. In addition, the Do Ping bit is set in the HCTSIZ register. In this case, the controller performs the entire PING protocol, then starts the data transfer.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
hc Information needed to initialize the host channel. The xfer_len value may be reduced to accommodate the max widths of the XferSize and PktCnt fields in the HCTSIZn register. The multi_count value may be changed to reflect the final xfer_len value.
+
+ +

+Definition at line 1800 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hc_start_transfer_ddma (dwc_otg_core_if_t core_if,
dwc_hc_t hc 
)
+
+
+ +

+This function does the setup for a data transfer for a host channel and starts the transfer in Descriptor DMA mode. +

+Initializes HCTSIZ register. For a PING transfer the Do Ping bit is set. Sets PID and NTD values. For periodic transfers initializes SCHED_INFO field with micro-frame bitmap.

+Initializes HCDMA register with descriptor list address and CTD value then starts the transfer via enabling the channel.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
hc Information needed to initialize the host channel.
+
+ +

+Definition at line 1968 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_hc_continue_transfer (dwc_otg_core_if_t core_if,
dwc_hc_t hc 
)
+
+
+ +

+This function continues a data transfer that was started by previous call to dwc_otg_hc_start_transfer. +

+The caller must ensure there is sufficient space in the request queue and Tx Data FIFO. This function should only be called in Slave mode. In DMA mode, the controller acts autonomously to complete transfers programmed to a host channel.

+For an OUT transfer, a new data packet is loaded into the appropriate FIFO if there is any data remaining to be queued. For an IN transfer, another data packet is always requested. For the SETUP phase of a control transfer, this function does nothing.

+

Returns:
1 if a new request is queued, 0 if no more requests are required for this transfer.
+ +

+Definition at line 2048 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hc_do_ping (dwc_otg_core_if_t core_if,
dwc_hc_t hc 
)
+
+
+ +

+Starts a PING transfer. +

+This function should only be called in Slave mode. The Do Ping bit is set in the HCTSIZ register, then the channel is enabled. +

+Definition at line 2110 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
uint32_t dwc_otg_get_frame_number (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+Gets the current USB frame number. +

+This is the frame number from the last SOF packet. +

+Definition at line 2182 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_read_setup_packet (dwc_otg_core_if_t core_if,
uint32_t *  dest 
)
+
+
+ +

+This function reads a setup packet from the Rx FIFO into the destination buffer. +

+This function is called from the Rx Status Queue Level (RxStsQLvl) Interrupt routine when a SETUP packet has been received in Slave mode.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
dest Destination buffer for packet data.
+
+ +

+Definition at line 2199 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_ep0_activate (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function enables EP0 OUT to receive SETUP packets and configures EP0 IN for transmitting packets. +

+It is normally called when the "Enumeration Done" interrupt occurs.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP0 data.
+
+ +

+Definition at line 2216 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_ep_activate (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function activates an EP. +

+The Device EP control register for the EP is configured as defined in the ep structure. Note: This function is not used for EP0.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to activate.
+
+ +

+Definition at line 2268 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_ep_deactivate (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function deactivates an EP. +

+This is done by clearing the USB Active EP bit in the Device EP control register. Note: This function is not used for EP0. EP0 cannot be deactivated.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to deactivate.
+
+ +

+Definition at line 2367 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static void init_dma_desc_chain (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
) [static]
+
+
+ +

+This function initializes dma descriptor chain. +

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to start the transfer on.
+
+ +

+DMA Descriptor Setup +

+Definition at line 2415 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_ep_start_transfer (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function does the setup for a data transfer for an EP and starts the transfer. +

+For an IN transfer, the packets will be loaded into the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are unloaded from the Rx FIFO in the ISR. the ISR.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to start the transfer on.
+
+ +

+DIEPDMAn Register write

+Enable the Non-Periodic Tx FIFO empty interrupt, or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode, the data will be written into the fifo by the ISR.

+DOEPDMAn Register write +

+Definition at line 2475 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_ep_start_zl_transfer (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function setup a zero length transfer in Buffer DMA and Slave modes for usb requests with zero field set. +

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to start the transfer on.
+
+ +

+Enable the Non-Periodic Tx FIFO empty interrupt, or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode, the data will be written into the fifo by the ISR. +

+Definition at line 2678 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_ep0_start_transfer (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function does the setup for a data transfer for EP0 and starts the transfer. +

+For an IN transfer, the packets will be loaded into the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are unloaded from the Rx FIFO in the ISR.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP0 data.
+
+ +

+DMA Descriptor Setup

+DIEPDMA0 Register write

+Enable the Non-Periodic Tx FIFO empty interrupt, the data will be written into the fifo by the ISR.

+DMA Descriptor Setup

+DOEPDMA0 Register write +

+Definition at line 2785 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_ep0_continue_transfer (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function continues control IN transfers started by dwc_otg_ep0_start_transfer, when the transfer does not fit in a single packet. +

+NOTE: The DIEPCTL0/DOEPCTL0 registers only have one bit for the packet count.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP0 data.
+
+ +

+

Todo:
Should there be check for room in the Tx Status Queue. If not remove the code above this comment.
+

+DMA Descriptor Setup

+DIEPDMA0 Register write

+Enable the Non-Periodic Tx FIFO empty interrupt, the data will be written into the fifo by the ISR.

+DMA Descriptor Setup

+DOEPDMA0 Register write +

+Definition at line 2969 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_ep_write_packet (dwc_otg_core_if_t core_if,
dwc_ep_t ep,
int  dma 
)
+
+
+ +

+This function writes a packet into the Tx FIFO associated with the EP. +

+For non-periodic EPs the non-periodic Tx FIFO is written. For periodic EPs the periodic Tx FIFO associated with the EP is written with all packets for the next micro-frame.

+

Parameters:
+ + + + +
core_if Programming view of DWC_otg controller.
ep The EP to write packet for.
dma Indicates if DMA is being used.
+
+ +

+The buffer is padded to DWORD on a per packet basis in slave/dma mode if the MPS is not DWORD aligned. The last packet, if short, is also padded to a multiple of DWORD.

+ep->xfer_buff always starts DWORD aligned in memory and is a multiple of DWORD in length

+ep->xfer_len can be any number of bytes

+ep->xfer_count is a multiple of ep->maxpacket until the last packet

+FIFO access is DWORD

+

Todo:
NGS Where are the Periodic Tx FIFO addresses intialized? What should this be?
+ +

+Definition at line 3165 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_ep_set_stall (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+Set the EP STALL. +

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to set the stall on.
+
+ +

+Definition at line 3236 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_ep_clear_stall (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+Clear the EP STALL. +

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to clear stall from.
+
+ +

+Definition at line 3274 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_read_packet (dwc_otg_core_if_t core_if,
uint8_t *  dest,
uint16_t  bytes 
)
+
+
+ +

+This function reads a packet from the Rx FIFO into the destination buffer. +

+To read SETUP data use dwc_otg_read_setup_packet.

+

Parameters:
+ + + + +
core_if Programming view of DWC_otg controller.
dest Destination buffer for the packet.
bytes Number of bytes to copy to the destination.
+
+ +

+

Todo:
Account for the case where _dest is not dword aligned. This requires reading data from the FIFO into a uint32_t temp buffer, then moving it into the data buffer.
+ +

+Definition at line 3317 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_dump_dev_registers (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+Dump core registers and SPRAM. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 3347 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_dump_spram (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This functions reads the SPRAM and prints its content. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 3477 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_dump_host_registers (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function reads the host registers and prints them. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 3505 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_dump_global_registers (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function reads the core global registers and prints them. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 3573 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_flush_tx_fifo (dwc_otg_core_if_t core_if,
const int  num 
)
+
+
+ +

+Flush a Tx FIFO. +

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
num Tx FIFO to flush.
+
+ +

+Definition at line 3662 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_flush_rx_fifo (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+Flush Rx FIFO. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 3694 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_core_reset (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+Do core a soft reset of the core. +

+Be careful with this because it resets all the internal state machines of the core. +

+Definition at line 3725 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_cil_register_hcd_callbacks (dwc_otg_core_if_t core_if,
dwc_otg_cil_callbacks_t cb,
void *  p 
)
+
+
+ +

+Register HCD callbacks. +

+The callbacks are used to start and stop the HCD for interrupt processing.

+

Parameters:
+ + + + +
core_if Programming view of DWC_otg controller.
cb the HCD callback structure.
p pointer to be passed to callback function (usb_hcd*).
+
+ +

+Definition at line 3781 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_cil_register_pcd_callbacks (dwc_otg_core_if_t core_if,
dwc_otg_cil_callbacks_t cb,
void *  p 
)
+
+
+ +

+Register PCD callbacks. +

+The callbacks are used to start and stop the PCD for interrupt processing.

+

Parameters:
+ + + + +
core_if Programming view of DWC_otg controller.
cb the PCD callback structure.
p pointer to be passed to callback function (pcd*).
+
+ +

+Definition at line 3796 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void write_isoc_frame_data (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function writes isoc data per 1 (micro)frame into tx fifo. +

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to start the transfer on.
+
+ +

+Definition at line 3812 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_iso_ep_start_frm_transfer (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function initializes a descriptor chain for Isochronous transfer. +

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to start the transfer on.
+
+ +

+Enable endpoint, clear nak +

+Definition at line 3864 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_otg_cap (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Specifies the OTG capabilities. +

+The driver will automatically detect the value for this parameter if none is specified. 0 - HNP and SRP capable (default) 1 - SRP Only capable 2 - No HNP/SRP capable +

+Definition at line 4056 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_dma_enable (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Specifies whether to use slave or DMA mode for accessing the data FIFOs. +

+The driver will automatically detect the value for this parameter if none is specified. 0 - Slave 1 - DMA (default, if available) +

+Definition at line 4135 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_dma_desc_enable (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+When DMA mode is enabled specifies whether to use address DMA or DMA Descritor mode for accessing the data FIFOs in device mode. +

+The driver will automatically detect the value for this parameter if none is specified. 0 - address DMA 1 - DMA Descriptor(default, if available) +

+Definition at line 4165 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_host_support_fs_ls_low_power (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Specifies whether low power mode is supported when attached to a Full Speed or Low Speed device in host mode. +

+0 - Don't support low power mode (default) 1 - Support low power mode +

+Definition at line 4195 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_data_fifo_size (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Total number of 4-byte words in the data FIFO memory. +

+This memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic Tx FIFOs. 32 to 32768 (default 8192) Note: The total FIFO memory depth in the FPGA configuration is 8192. +

+Definition at line 4242 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_dev_rx_fifo_size (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Number of 4-byte words in the Rx FIFO in device mode when dynamic FIFO sizing is enabled. +

+16 to 32768 (default 1064) +

+Definition at line 4271 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_dev_nperio_tx_fifo_size (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Number of 4-byte words in the non-periodic Tx FIFO in device mode when dynamic FIFO sizing is enabled. +

+16 to 32768 (default 1024) +

+Definition at line 4297 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_host_rx_fifo_size (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Number of 4-byte words in the Rx FIFO in host mode when dynamic FIFO sizing is enabled. +

+16 to 32768 (default 1024) +

+Definition at line 4330 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_host_nperio_tx_fifo_size (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Number of 4-byte words in the non-periodic Tx FIFO in host mode when Dynamic FIFO sizing is enabled in the core. +

+16 to 32768 (default 1024) +

+Definition at line 4362 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_host_perio_tx_fifo_size (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Number of 4-byte words in the host periodic Tx FIFO when dynamic FIFO sizing is enabled. +

+16 to 32768 (default 1024) +

+Definition at line 4395 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_max_transfer_size (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+The maximum transfer size supported in bytes. +

+2047 to 65,535 (default 65,535) +

+Definition at line 4428 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_max_packet_count (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+The maximum number of packets in a transfer. +

+15 to 511 (default 511) +

+Definition at line 4461 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_host_channels (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+The number of host channel registers to use. +

+1 to 16 (default 12) Note: The FPGA configuration supports a maximum of 12 host channels. +

+Definition at line 4492 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_dev_endpoints (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+The number of endpoints in addition to EP0 available for device mode operations. +

+1 to 15 (default 6 IN and OUT) Note: The FPGA configuration supports a maximum of 6 IN and OUT endpoints in addition to EP0. +

+Definition at line 4522 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_phy_type (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Specifies the type of PHY interface to use. +

+By default, the driver will automatically detect the phy_type.

+0 - Full Speed PHY 1 - UTMI+ (default) 2 - ULPI +

+Definition at line 4552 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_speed (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Specifies the maximum speed of operation in host and device mode. +

+The actual speed depends on the speed of the attached device and the value of phy_type. The actual speed depends on the speed of the attached device. 0 - High Speed (default) 1 - Full Speed +

+Definition at line 4601 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_host_ls_low_power_phy_clk (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Specifies the PHY clock rate in low power mode when connected to a Low Speed device in host mode. +

+This parameter is applicable only if HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS then defaults to 6 MHZ otherwise 48 MHZ.

+0 - 48 MHz 1 - 6 MHz +

+Definition at line 4630 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_phy_ulpi_ddr (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Specifies whether the ULPI operates at double or single data rate. +

+This parameter is only applicable if PHY_TYPE is ULPI.

+0 - single data rate ULPI interface with 8 bit wide data bus (default) 1 - double data rate ULPI interface with 4 bit wide data bus +

+Definition at line 4665 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_phy_utmi_width (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Specifies the UTMI+ Data Width. +

+This parameter is applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI PHY_TYPE, this parameter indicates the data width between the MAC and the ULPI Wrapper.) Also, this parameter is applicable only if the OTG_HSPHY_WIDTH cC parameter was set to "8 and 16 bits", meaning that the core has been configured to work at either data path width.

+8 or 16 bits (default 16) +

+Definition at line 4700 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_i2c_enable (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Specifies whether to use the I2Cinterface for full speed PHY. +

+This parameter is only applicable if PHY_TYPE is FS. 0 - No (default) 1 - Yes +

+Definition at line 4751 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_dev_perio_tx_fifo_size (dwc_otg_core_if_t core_if,
int32_t  val,
int  fifo_num 
)
+
+
+ +

+Number of 4-byte words in each of the periodic Tx FIFOs in device mode when dynamic FIFO sizing is enabled. +

+4 to 768 (default 256) +

+Definition at line 4779 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_dma_burst_size (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+The DMA Burst size (applicable only for External DMA Mode). +

+1, 4, 8 16, 32, 64, 128, 256 (default 32) +

+Definition at line 4959 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
uint32_t dwc_otg_get_mode (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+Get current mode. +

+Returns 0 if in device mode, and 1 if in host mode. +

+Definition at line 5115 of file dwc_otg_cil.c. +

+

+


Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil_8h-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil_8h-source.html new file mode 100644 index 000000000000..bfe829d972e0 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil_8h-source.html @@ -0,0 +1,709 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_cil.h Source File + + + + + + +

dwc_otg_cil.h

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.h $
+00003  * $Revision: #99 $
+00004  * $Date: 2009/04/21 $
+00005  * $Change: 1237466 $
+00006  *
+00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009  * otherwise expressly agreed to in writing between Synopsys and you.
+00010  * 
+00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012  * any End User Software License Agreement or Agreement for Licensed Product
+00013  * with Synopsys or any supplement thereto. You are permitted to use and
+00014  * redistribute this Software in source and binary forms, with or without
+00015  * modification, provided that redistributions of source code must retain this
+00016  * notice. You may not view, use, disclose, copy or distribute this file or
+00017  * any information contained herein except pursuant to this license grant from
+00018  * Synopsys. If you do not agree with this notice, including the disclaimer
+00019  * below, then you are not authorized to use the Software.
+00020  * 
+00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031  * DAMAGE.
+00032  * ========================================================================== */
+00033 
+00034 #if !defined(__DWC_CIL_H__)
+00035 #define __DWC_CIL_H__
+00036 
+00037 #include "dwc_os.h"
+00038 #include "dwc_list.h"
+00039 #include "dwc_otg_dbg.h"
+00040 #include "dwc_otg_regs.h"
+00041 
+00042 #include "dwc_otg_core_if.h"
+00043 
+00049 #ifdef DWC_UTE_CFI
+00050 
+00051 #define MAX_DMA_DESCS_PER_EP    256
+00052 
+00056 typedef enum _data_buffer_mode {
+00057         BM_STANDARD = 0,        /* data buffer is in normal mode */
+00058         BM_SG = 1,              /* data buffer uses the scatter/gather mode */
+00059         BM_CONCAT = 2,          /* data buffer uses the concatenation mode */
+00060         BM_CIRCULAR = 3,        /* data buffer uses the circular DMA mode */
+00061         BM_ALIGN = 4            /* data buffer is in buffer alignment mode */
+00062 } data_buffer_mode_e;
+00063 #endif                          //DWC_UTE_CFI
+00064 
+00067 #define OTG_CORE_REV_2_60a      0x4F54260A
+00068 #define OTG_CORE_REV_2_71a      0x4F54271A
+00069 #define OTG_CORE_REV_2_72a      0x4F54272A
+00070 #define OTG_CORE_REV_2_80a      0x4F54280A
+00071 #define OTG_CORE_REV_2_81a      0x4F54281A
+00072 #define OTG_CORE_REV_2_90a      0x4F54290A              
+00073 
+00077 typedef struct iso_pkt_info {
+00078         uint32_t offset;
+00079         uint32_t length;
+00080         int32_t status;
+00081 } iso_pkt_info_t;
+00082 
+00088 typedef struct dwc_ep {
+00090         uint8_t num;
+00092         unsigned is_in:1;
+00094         unsigned active:1;
+00095 
+00098         unsigned tx_fifo_num:4;
+00100         unsigned type:2;
+00101 #define DWC_OTG_EP_TYPE_CONTROL    0
+00102 #define DWC_OTG_EP_TYPE_ISOC       1
+00103 #define DWC_OTG_EP_TYPE_BULK       2
+00104 #define DWC_OTG_EP_TYPE_INTR       3
+00105 
+00107         unsigned data_pid_start:1;
+00109         unsigned even_odd_frame:1;
+00111         unsigned maxpacket:11;
+00112 
+00114         uint32_t maxxfer;
+00115 
+00124         dwc_dma_t dma_addr;
+00125 
+00126         dwc_dma_t dma_desc_addr;
+00127         dwc_otg_dev_dma_desc_t *desc_addr;
+00128 
+00129         uint8_t *start_xfer_buff;
+00131         uint8_t *xfer_buff;
+00133         unsigned xfer_len:19;
+00135         unsigned xfer_count:19;
+00137         unsigned sent_zlp:1;
+00139         unsigned total_len:19;
+00140 
+00142         unsigned stall_clear_flag:1;
+00143 
+00144 #ifdef DWC_UTE_CFI
+00145         /* The buffer mode */
+00146         data_buffer_mode_e buff_mode;
+00147 
+00148         /* The chain of DMA descriptors.
+00149          * MAX_DMA_DESCS_PER_EP will be allocated for each active EP.
+00150          */
+00151         dwc_otg_dma_desc_t *descs;
+00152 
+00153         /* The DMA address of the descriptors chain start */
+00154         dma_addr_t descs_dma_addr;
+00156         uint32_t cfi_req_len;
+00157 #endif                          //DWC_UTE_CFI
+00158 
+00160         uint32_t desc_cnt;
+00161 
+00162 #ifdef DWC_EN_ISOC
+00163 
+00168         dwc_dma_t dma_addr0;
+00169         dwc_dma_t dma_addr1;
+00170 
+00171         dwc_dma_t iso_dma_desc_addr;
+00172         dwc_otg_dev_dma_desc_t *iso_desc_addr;
+00173 
+00175         uint8_t *xfer_buff0;
+00176         uint8_t *xfer_buff1;
+00177 
+00179         uint32_t proc_buf_num;
+00181         uint32_t buf_proc_intrvl;
+00183         uint32_t data_per_frame;
+00184 
+00185         /* todo - pattern data support is to be implemented in the future */
+00187         uint32_t data_pattern_frame;
+00189         uint32_t sync_frame;
+00190 
+00192         uint32_t bInterval;
+00194         uint32_t pkt_per_frm;
+00196         uint32_t next_frame;
+00198         uint32_t pkt_cnt;
+00200         iso_pkt_info_t *pkt_info;
+00202         uint32_t cur_pkt;
+00204         uint8_t *cur_pkt_addr;
+00206         uint32_t cur_pkt_dma_addr;
+00207 #endif                          /* DWC_EN_ISOC */
+00208 
+00210 } dwc_ep_t;
+00211 
+00212 /*
+00213  * Reasons for halting a host channel.
+00214  */
+00215 typedef enum dwc_otg_halt_status {
+00216         DWC_OTG_HC_XFER_NO_HALT_STATUS,
+00217         DWC_OTG_HC_XFER_COMPLETE,
+00218         DWC_OTG_HC_XFER_URB_COMPLETE,
+00219         DWC_OTG_HC_XFER_ACK,
+00220         DWC_OTG_HC_XFER_NAK,
+00221         DWC_OTG_HC_XFER_NYET,
+00222         DWC_OTG_HC_XFER_STALL,
+00223         DWC_OTG_HC_XFER_XACT_ERR,
+00224         DWC_OTG_HC_XFER_FRAME_OVERRUN,
+00225         DWC_OTG_HC_XFER_BABBLE_ERR,
+00226         DWC_OTG_HC_XFER_DATA_TOGGLE_ERR,
+00227         DWC_OTG_HC_XFER_AHB_ERR,
+00228         DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE,
+00229         DWC_OTG_HC_XFER_URB_DEQUEUE
+00230 } dwc_otg_halt_status_e;
+00231 
+00237 typedef struct dwc_hc {
+00239         uint8_t hc_num;
+00240 
+00242         unsigned dev_addr:7;
+00243 
+00245         unsigned ep_num:4;
+00246 
+00248         unsigned ep_is_in:1;
+00249 
+00257         unsigned speed:2;
+00258 #define DWC_OTG_EP_SPEED_LOW    0
+00259 #define DWC_OTG_EP_SPEED_FULL   1
+00260 #define DWC_OTG_EP_SPEED_HIGH   2
+00261 
+00270         unsigned ep_type:2;
+00271 
+00273         unsigned max_packet:11;
+00274 
+00283         unsigned data_pid_start:2;
+00284 #define DWC_OTG_HC_PID_DATA0 0
+00285 #define DWC_OTG_HC_PID_DATA2 1
+00286 #define DWC_OTG_HC_PID_DATA1 2
+00287 #define DWC_OTG_HC_PID_MDATA 3
+00288 #define DWC_OTG_HC_PID_SETUP 3
+00289 
+00291         unsigned multi_count:2;
+00292 
+00297         uint8_t *xfer_buff;
+00302         dwc_dma_t align_buff;
+00304         uint32_t xfer_len;
+00306         uint32_t xfer_count;
+00308         uint16_t start_pkt_count;
+00309 
+00314         uint8_t xfer_started;
+00315 
+00320         uint8_t do_ping;
+00321 
+00326         uint8_t error_state;
+00327 
+00334         uint8_t halt_on_queue;
+00335 
+00340         uint8_t halt_pending;
+00341 
+00345         dwc_otg_halt_status_e halt_status;
+00346 
+00347         /*
+00348          * Split settings for the host channel
+00349          */
+00350         uint8_t do_split;                  
+00351         uint8_t complete_split;    
+00352         uint8_t hub_addr;                  
+00354         uint8_t port_addr;                 
+00361         uint8_t xact_pos;
+00362 
+00364         uint8_t short_read;
+00365 
+00370         uint8_t requests;
+00371 
+00375         struct dwc_otg_qh *qh;
+00376 
+00380          DWC_CIRCLEQ_ENTRY(dwc_hc) hc_list_entry;
+00381         
+00386         uint16_t ntd;
+00387         
+00389         dwc_dma_t desc_list_addr;
+00390         
+00392         uint8_t schinfo;
+00393         
+00395 } dwc_hc_t;
+00396 
+00401 typedef struct dwc_otg_core_params {
+00402         int32_t opt;
+00403 
+00411         int32_t otg_cap;
+00412 
+00420         int32_t dma_enable;
+00421 
+00429         int32_t dma_desc_enable;
+00433         int32_t dma_burst_size; /* Translate this to GAHBCFG values */
+00434 
+00443         int32_t speed;
+00449         int32_t host_support_fs_ls_low_power;
+00450 
+00459         int32_t host_ls_low_power_phy_clk;
+00460 
+00465         int32_t enable_dynamic_fifo;
+00466 
+00473         int32_t data_fifo_size;
+00474 
+00479         int32_t dev_rx_fifo_size;
+00480 
+00485         int32_t dev_nperio_tx_fifo_size;
+00486 
+00491         uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
+00492 
+00497         int32_t host_rx_fifo_size;
+00498 
+00503         int32_t host_nperio_tx_fifo_size;
+00504 
+00509         int32_t host_perio_tx_fifo_size;
+00510 
+00514         int32_t max_transfer_size;
+00515 
+00519         int32_t max_packet_count;
+00520 
+00525         int32_t host_channels;
+00526 
+00533         int32_t dev_endpoints;
+00534 
+00543         int32_t phy_type;
+00544 
+00556         int32_t phy_utmi_width;
+00557 
+00568         int32_t phy_ulpi_ddr;
+00569 
+00574         int32_t phy_ulpi_ext_vbus;
+00575 
+00582         int32_t i2c_enable;
+00583 
+00584         int32_t ulpi_fs_ls;
+00585 
+00586         int32_t ts_dline;
+00587 
+00594         int32_t en_multiple_tx_fifo;
+00595 
+00600         uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
+00601 
+00607         uint32_t thr_ctl;
+00608 
+00612         uint32_t tx_thr_length;
+00613 
+00617         uint32_t rx_thr_length;
+00618 
+00622         int32_t lpm_enable;
+00623 
+00629         int32_t pti_enable;
+00630 
+00636         int32_t mpi_enable;
+00637 
+00642         int32_t ic_usb_cap;
+00643 
+00650         int32_t ahb_thr_ratio;
+00651 
+00652 } dwc_otg_core_params_t;
+00653 
+00654 #ifdef DEBUG
+00655 struct dwc_otg_core_if;
+00656 typedef struct hc_xfer_info {
+00657         struct dwc_otg_core_if *core_if;
+00658         dwc_hc_t *hc;
+00659 } hc_xfer_info_t;
+00660 #endif
+00661 /*
+00662  * Device States
+00663  */
+00664 typedef enum dwc_otg_lx_state {
+00666         DWC_OTG_L0,
+00668         DWC_OTG_L1,
+00670         DWC_OTG_L2,
+00672         DWC_OTG_L3
+00673 } dwc_otg_lx_state_e;
+00674 
+00680 struct dwc_otg_core_if {
+00682         dwc_otg_core_params_t *core_params;
+00683 
+00685         dwc_otg_core_global_regs_t *core_global_regs;
+00686 
+00688         dwc_otg_dev_if_t *dev_if;
+00690         dwc_otg_host_if_t *host_if;
+00691 
+00693         uint32_t snpsid;
+00694 
+00695         /*
+00696          * Set to 1 if the core PHY interface bits in USBCFG have been
+00697          * initialized.
+00698          */
+00699         uint8_t phy_init_done;
+00700 
+00701         /*
+00702          * SRP Success flag, set by srp success interrupt in FS I2C mode
+00703          */
+00704         uint8_t srp_success;
+00705         uint8_t srp_timer_started;
+00706 
+00707         /* Common configuration information */
+00709         volatile uint32_t *pcgcctl;
+00710 #define DWC_OTG_PCGCCTL_OFFSET 0xE00
+00711 
+00713         uint32_t *data_fifo[MAX_EPS_CHANNELS];
+00714 #define DWC_OTG_DATA_FIFO_OFFSET 0x1000
+00715 #define DWC_OTG_DATA_FIFO_SIZE 0x1000
+00716 
+00718         uint16_t total_fifo_size;
+00720         uint16_t rx_fifo_size;
+00722         uint16_t nperio_tx_fifo_size;
+00723 
+00725         uint8_t dma_enable;
+00726 
+00728         uint8_t dma_desc_enable;
+00729 
+00731         uint8_t pti_enh_enable;
+00732 
+00734         uint8_t multiproc_int_enable;
+00735 
+00737         uint8_t en_multiple_tx_fifo;
+00738 
+00741         uint8_t queuing_high_bandwidth;
+00742 
+00744         hwcfg1_data_t hwcfg1;
+00745         hwcfg2_data_t hwcfg2;
+00746         hwcfg3_data_t hwcfg3;
+00747         hwcfg4_data_t hwcfg4;
+00748 
+00750         hcfg_data_t hcfg;
+00751         dcfg_data_t dcfg;
+00752 
+00758         uint8_t op_state;
+00759 
+00765         uint8_t restart_hcd_on_session_req;
+00766 
+00769 #define A_HOST          (1)
+00770 
+00771 #define A_SUSPEND       (2)
+00772 
+00773 #define A_PERIPHERAL    (3)
+00774 
+00775 #define B_PERIPHERAL    (4)
+00776 
+00777 #define B_HOST          (5)
+00778 
+00780         struct dwc_otg_cil_callbacks *hcd_cb;
+00782         struct dwc_otg_cil_callbacks *pcd_cb;
+00783 
+00785         uint32_t p_tx_msk;
+00787         uint32_t tx_msk;
+00788 
+00790         dwc_workq_t *wq_otg;
+00791 
+00793         dwc_timer_t *wkp_timer;
+00794 
+00795 #ifdef DEBUG
+00796         uint32_t start_hcchar_val[MAX_EPS_CHANNELS];
+00797 
+00798         hc_xfer_info_t hc_xfer_info[MAX_EPS_CHANNELS];
+00799         dwc_timer_t *hc_xfer_timer[MAX_EPS_CHANNELS];
+00800 
+00801         uint32_t hfnum_7_samples;
+00802         uint64_t hfnum_7_frrem_accum;
+00803         uint32_t hfnum_0_samples;
+00804         uint64_t hfnum_0_frrem_accum;
+00805         uint32_t hfnum_other_samples;
+00806         uint64_t hfnum_other_frrem_accum;
+00807 #endif
+00808 
+00809 #ifdef DWC_UTE_CFI
+00810         uint16_t pwron_rxfsiz;
+00811         uint16_t pwron_gnptxfsiz;
+00812         uint16_t pwron_txfsiz[15];
+00813 
+00814         uint16_t init_rxfsiz;
+00815         uint16_t init_gnptxfsiz;
+00816         uint16_t init_txfsiz[15];
+00817 #endif
+00818 
+00820         dwc_otg_lx_state_e lx_state;
+00821 
+00822 };
+00823 
+00824 #ifdef DEBUG
+00825 /*
+00826  * This function is called when transfer is timed out.
+00827  */
+00828 extern void hc_xfer_timeout(void *ptr);
+00829 #endif
+00830 
+00831 /*
+00832  * The following functions are functions for works 
+00833  * using during handling some interrupts
+00834  */
+00835 extern void w_conn_id_status_change(void *p);
+00836 
+00837 extern void w_wakeup_detected(void *p);
+00838 
+00839 /*
+00840  * The following functions support initialization of the CIL driver component
+00841  * and the DWC_otg controller.
+00842  */
+00843 extern void dwc_otg_core_host_init(dwc_otg_core_if_t * _core_if);
+00844 extern void dwc_otg_core_dev_init(dwc_otg_core_if_t * _core_if);
+00845 
+00851 extern void dwc_otg_wakeup(dwc_otg_core_if_t * _core_if);
+00852 extern void dwc_otg_read_setup_packet(dwc_otg_core_if_t * _core_if,
+00853                                       uint32_t * _dest);
+00854 extern uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * _core_if);
+00855 extern void dwc_otg_ep0_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
+00856 extern void dwc_otg_ep_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
+00857 extern void dwc_otg_ep_deactivate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
+00858 extern void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * _core_if,
+00859                                       dwc_ep_t * _ep);
+00860 extern void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * _core_if,
+00861                                          dwc_ep_t * _ep);
+00862 extern void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * _core_if,
+00863                                        dwc_ep_t * _ep);
+00864 extern void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * _core_if,
+00865                                           dwc_ep_t * _ep);
+00866 extern void dwc_otg_ep_write_packet(dwc_otg_core_if_t * _core_if,
+00867                                     dwc_ep_t * _ep, int _dma);
+00868 extern void dwc_otg_ep_set_stall(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep);
+00869 extern void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * _core_if,
+00870                                    dwc_ep_t * _ep);
+00871 extern void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * _core_if);
+00872 
+00873 #ifdef DWC_EN_ISOC
+00874 extern void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if,
+00875                                               dwc_ep_t * ep);
+00876 extern void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
+00877                                               dwc_ep_t * ep);
+00878 #endif                          /* DWC_EN_ISOC */
+00879 
+00886 extern void dwc_otg_hc_init(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
+00887 extern void dwc_otg_hc_halt(dwc_otg_core_if_t * _core_if,
+00888                             dwc_hc_t * _hc, dwc_otg_halt_status_e _halt_status);
+00889 extern void dwc_otg_hc_cleanup(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
+00890 extern void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * _core_if,
+00891                                       dwc_hc_t * _hc);
+00892 extern int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * _core_if,
+00893                                         dwc_hc_t * _hc);
+00894 extern void dwc_otg_hc_do_ping(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc);
+00895 extern void dwc_otg_hc_write_packet(dwc_otg_core_if_t * _core_if,
+00896                                     dwc_hc_t * _hc);
+00897 extern void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * _core_if);
+00898 extern void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * _core_if);
+00899 
+00900 extern void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if, dwc_hc_t * hc);
+00901 
+00902 /* Macro used to clear one channel interrupt */
+00903 #define clear_hc_int(_hc_regs_, _intr_) \
+00904 do { \
+00905         hcint_data_t hcint_clear = {.d32 = 0}; \
+00906         hcint_clear.b._intr_ = 1; \
+00907         dwc_write_reg32(&(_hc_regs_)->hcint, hcint_clear.d32); \
+00908 } while (0)
+00909 
+00910 /*
+00911  * Macro used to disable one channel interrupt. Channel interrupts are
+00912  * disabled when the channel is halted or released by the interrupt handler.
+00913  * There is no need to handle further interrupts of that type until the
+00914  * channel is re-assigned. In fact, subsequent handling may cause crashes
+00915  * because the channel structures are cleaned up when the channel is released.
+00916  */
+00917 #define disable_hc_int(_hc_regs_, _intr_) \
+00918 do { \
+00919         hcintmsk_data_t hcintmsk = {.d32 = 0}; \
+00920         hcintmsk.b._intr_ = 1; \
+00921         dwc_modify_reg32(&(_hc_regs_)->hcintmsk, hcintmsk.d32, 0); \
+00922 } while (0)
+00923                 
+00929 static inline uint32_t dwc_otg_read_hprt0(dwc_otg_core_if_t * _core_if)
+00930 {
+00931         hprt0_data_t hprt0;
+00932         hprt0.d32 = dwc_read_reg32(_core_if->host_if->hprt0);
+00933         hprt0.b.prtena = 0;
+00934         hprt0.b.prtconndet = 0;
+00935         hprt0.b.prtenchng = 0;
+00936         hprt0.b.prtovrcurrchng = 0;
+00937         return hprt0.d32;
+00938 }
+00939 
+00948 extern void dwc_otg_read_packet(dwc_otg_core_if_t * core_if,
+00949                                 uint8_t * dest, uint16_t bytes);
+00950 
+00951 extern void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * _core_if, const int _num);
+00952 extern void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * _core_if);
+00953 extern void dwc_otg_core_reset(dwc_otg_core_if_t * _core_if);
+00954 
+00958 static inline uint32_t dwc_otg_read_core_intr(dwc_otg_core_if_t * core_if)
+00959 {
+00960         return (dwc_read_reg32(&core_if->core_global_regs->gintsts) &
+00961                 dwc_read_reg32(&core_if->core_global_regs->gintmsk));
+00962 }
+00963 
+00967 static inline uint32_t dwc_otg_read_otg_intr(dwc_otg_core_if_t * core_if)
+00968 {
+00969         return (dwc_read_reg32(&core_if->core_global_regs->gotgint));
+00970 }
+00971 
+00976 static inline uint32_t dwc_otg_read_dev_all_in_ep_intr(dwc_otg_core_if_t *
+00977                                                        core_if)
+00978 {
+00979 
+00980         uint32_t v;
+00981 
+00982         if (core_if->multiproc_int_enable) {
+00983                 v = dwc_read_reg32(&core_if->dev_if->dev_global_regs->
+00984                                    deachint) & dwc_read_reg32(&core_if->dev_if->
+00985                                                               dev_global_regs->
+00986                                                               deachintmsk);
+00987         } else {
+00988                 v = dwc_read_reg32(&core_if->dev_if->dev_global_regs->daint) &
+00989                     dwc_read_reg32(&core_if->dev_if->dev_global_regs->daintmsk);
+00990         }
+00991         return (v & 0xffff);
+00992 }
+00993 
+00998 static inline uint32_t dwc_otg_read_dev_all_out_ep_intr(dwc_otg_core_if_t *
+00999                                                         core_if)
+01000 {
+01001         uint32_t v;
+01002 
+01003         if (core_if->multiproc_int_enable) {
+01004                 v = dwc_read_reg32(&core_if->dev_if->dev_global_regs->
+01005                                    deachint) & dwc_read_reg32(&core_if->dev_if->
+01006                                                               dev_global_regs->
+01007                                                               deachintmsk);
+01008         } else {
+01009                 v = dwc_read_reg32(&core_if->dev_if->dev_global_regs->daint) &
+01010                     dwc_read_reg32(&core_if->dev_if->dev_global_regs->daintmsk);
+01011         }
+01012 
+01013         return ((v & 0xffff0000) >> 16);
+01014 }
+01015 
+01019 static inline uint32_t dwc_otg_read_dev_in_ep_intr(dwc_otg_core_if_t * core_if,
+01020                                                    dwc_ep_t * ep)
+01021 {
+01022         dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+01023         uint32_t v, msk, emp;
+01024 
+01025         if (core_if->multiproc_int_enable) {
+01026                 msk =
+01027                     dwc_read_reg32(&dev_if->dev_global_regs->
+01028                                    diepeachintmsk[ep->num]);
+01029                 emp =
+01030                     dwc_read_reg32(&dev_if->dev_global_regs->
+01031                                    dtknqr4_fifoemptymsk);
+01032                 msk |= ((emp >> ep->num) & 0x1) << 7;
+01033                 v = dwc_read_reg32(&dev_if->in_ep_regs[ep->num]->diepint) & msk;
+01034         } else {
+01035                 msk = dwc_read_reg32(&dev_if->dev_global_regs->diepmsk);
+01036                 emp =
+01037                     dwc_read_reg32(&dev_if->dev_global_regs->
+01038                                    dtknqr4_fifoemptymsk);
+01039                 msk |= ((emp >> ep->num) & 0x1) << 7;
+01040                 v = dwc_read_reg32(&dev_if->in_ep_regs[ep->num]->diepint) & msk;
+01041         }
+01042 
+01043         return v;
+01044 }
+01045 
+01049 static inline uint32_t dwc_otg_read_dev_out_ep_intr(dwc_otg_core_if_t *
+01050                                                     _core_if, dwc_ep_t * _ep)
+01051 {
+01052         dwc_otg_dev_if_t *dev_if = _core_if->dev_if;
+01053         uint32_t v;
+01054         doepmsk_data_t msk = {.d32 = 0 };
+01055 
+01056         if (_core_if->multiproc_int_enable) {
+01057                 msk.d32 =
+01058                     dwc_read_reg32(&dev_if->dev_global_regs->
+01059                                    doepeachintmsk[_ep->num]);
+01060                 if (_core_if->pti_enh_enable) {
+01061                         msk.b.pktdrpsts = 1;
+01062                 }
+01063                 v = dwc_read_reg32(&dev_if->out_ep_regs[_ep->num]->
+01064                                    doepint) & msk.d32;
+01065         } else {
+01066                 msk.d32 = dwc_read_reg32(&dev_if->dev_global_regs->doepmsk);
+01067                 if (_core_if->pti_enh_enable) {
+01068                         msk.b.pktdrpsts = 1;
+01069                 }
+01070                 v = dwc_read_reg32(&dev_if->out_ep_regs[_ep->num]->
+01071                                    doepint) & msk.d32;
+01072         }
+01073         return v;
+01074 }
+01075 
+01079 static inline uint32_t dwc_otg_read_host_all_channels_intr(dwc_otg_core_if_t *
+01080                                                            _core_if)
+01081 {
+01082         return (dwc_read_reg32(&_core_if->host_if->host_global_regs->haint));
+01083 }
+01084 
+01085 static inline uint32_t dwc_otg_read_host_channel_intr(dwc_otg_core_if_t *
+01086                                                       _core_if, dwc_hc_t * _hc)
+01087 {
+01088         return (dwc_read_reg32
+01089                 (&_core_if->host_if->hc_regs[_hc->hc_num]->hcint));
+01090 }
+01091 
+01097 static inline uint32_t dwc_otg_mode(dwc_otg_core_if_t * _core_if)
+01098 {
+01099         return (dwc_read_reg32(&_core_if->core_global_regs->gintsts) & 0x1);
+01100 }
+01101 
+01109 typedef struct dwc_otg_cil_callbacks {
+01111         int (*start) (void *_p);
+01113         int (*stop) (void *_p);
+01115         int (*disconnect) (void *_p);
+01117         int (*resume_wakeup) (void *_p);
+01119         int (*suspend) (void *_p);
+01121         int (*session_start) (void *_p);
+01122 #ifdef CONFIG_USB_DWC_OTG_LPM
+01123 
+01124         int (*sleep) (void *_p);
+01125 #endif
+01126 
+01127         void *p;
+01128 } dwc_otg_cil_callbacks_t;
+01129 
+01130 extern void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * _core_if,
+01131                                                dwc_otg_cil_callbacks_t * _cb,
+01132                                                void *_p);
+01133 extern void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * _core_if,
+01134                                                dwc_otg_cil_callbacks_t * _cb,
+01135                                                void *_p);
+01136 
+01137 #endif
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil_8h.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil_8h.html new file mode 100644 index 000000000000..708233e04595 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil_8h.html @@ -0,0 +1,1844 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_cil.h File Reference + + + + + + +

dwc_otg_cil.h File Reference

This file contains the interface to the Core Interface Layer. More... +

+#include "dwc_os.h"
+#include "dwc_list.h"
+#include "dwc_otg_dbg.h"
+#include "dwc_otg_regs.h"
+#include "dwc_otg_core_if.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Structures

struct  iso_pkt_info
 Information for each ISOC packet. More...
struct  dwc_ep
 The dwc_ep structure represents the state of a single endpoint when acting in device mode. More...
struct  dwc_hc
 Host channel descriptor. More...
struct  dwc_otg_core_params
 The following parameters may be specified when starting the module. More...
struct  dwc_otg_core_if
 The dwc_otg_core_if structure contains information needed to manage the DWC_otg controller acting in either host or device mode. More...
struct  dwc_otg_cil_callbacks
 DWC_otg CIL callback structure. More...

Host CIL Functions

The following functions support managing the DWC_otg controller in host mode.

#define clear_hc_int(_hc_regs_, _intr_)
#define disable_hc_int(_hc_regs_, _intr_)
void dwc_otg_hc_init (dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc)
 Prepares a host channel for transferring packets to/from a specific endpoint.
void dwc_otg_hc_halt (dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc, dwc_otg_halt_status_e _halt_status)
 Attempts to halt a host channel.
void dwc_otg_hc_cleanup (dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc)
 Clears the transfer state for a host channel.
void dwc_otg_hc_start_transfer (dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc)
 This function does the setup for a data transfer for a host channel and starts the transfer.
int dwc_otg_hc_continue_transfer (dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc)
 This function continues a data transfer that was started by previous call to dwc_otg_hc_start_transfer.
void dwc_otg_hc_do_ping (dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc)
 Starts a PING transfer.
+void dwc_otg_hc_write_packet (dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc)
void dwc_otg_enable_host_interrupts (dwc_otg_core_if_t *_core_if)
 This function enables the Host mode interrupts.
void dwc_otg_disable_host_interrupts (dwc_otg_core_if_t *_core_if)
 This function disables the Host Mode interrupts.
void dwc_otg_hc_start_transfer_ddma (dwc_otg_core_if_t *core_if, dwc_hc_t *hc)
 This function does the setup for a data transfer for a host channel and starts the transfer in Descriptor DMA mode.
static uint32_t dwc_otg_read_hprt0 (dwc_otg_core_if_t *_core_if)
 This function Reads HPRT0 in preparation to modify.

Device CIL Functions

The following functions support managing the DWC_otg controller in device mode.

+void dwc_otg_wakeup (dwc_otg_core_if_t *_core_if)
void dwc_otg_read_setup_packet (dwc_otg_core_if_t *_core_if, uint32_t *_dest)
 This function reads a setup packet from the Rx FIFO into the destination buffer.
uint32_t dwc_otg_get_frame_number (dwc_otg_core_if_t *_core_if)
 Gets the current USB frame number.
void dwc_otg_ep0_activate (dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep)
 This function enables EP0 OUT to receive SETUP packets and configures EP0 IN for transmitting packets.
void dwc_otg_ep_activate (dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep)
 This function activates an EP.
void dwc_otg_ep_deactivate (dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep)
 This function deactivates an EP.
void dwc_otg_ep_start_transfer (dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep)
 This function does the setup for a data transfer for an EP and starts the transfer.
void dwc_otg_ep_start_zl_transfer (dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep)
 This function setup a zero length transfer in Buffer DMA and Slave modes for usb requests with zero field set.
void dwc_otg_ep0_start_transfer (dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep)
 This function does the setup for a data transfer for EP0 and starts the transfer.
void dwc_otg_ep0_continue_transfer (dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep)
 This function continues control IN transfers started by dwc_otg_ep0_start_transfer, when the transfer does not fit in a single packet.
void dwc_otg_ep_write_packet (dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep, int _dma)
 This function writes a packet into the Tx FIFO associated with the EP.
void dwc_otg_ep_set_stall (dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep)
 Set the EP STALL.
void dwc_otg_ep_clear_stall (dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep)
 Clear the EP STALL.
void dwc_otg_enable_device_interrupts (dwc_otg_core_if_t *_core_if)
 This function enables the Device mode interrupts.
void dwc_otg_iso_ep_start_frm_transfer (dwc_otg_core_if_t *core_if, dwc_ep_t *ep)
 This function initializes a descriptor chain for Isochronous transfer.
void dwc_otg_iso_ep_start_buf_transfer (dwc_otg_core_if_t *core_if, dwc_ep_t *ep)
 This function initializes a descriptor chain for Isochronous transfer.

Common CIL Functions

The following functions support managing the DWC_otg controller in either device or host mode.

void dwc_otg_read_packet (dwc_otg_core_if_t *core_if, uint8_t *dest, uint16_t bytes)
 This function reads a packet from the Rx FIFO into the destination buffer.
void dwc_otg_flush_tx_fifo (dwc_otg_core_if_t *_core_if, const int _num)
 Flush a Tx FIFO.
void dwc_otg_flush_rx_fifo (dwc_otg_core_if_t *_core_if)
 Flush Rx FIFO.
void dwc_otg_core_reset (dwc_otg_core_if_t *_core_if)
 Do core a soft reset of the core.
+static uint32_t dwc_otg_read_core_intr (dwc_otg_core_if_t *core_if)
 This function returns the Core Interrupt register.
+static uint32_t dwc_otg_read_otg_intr (dwc_otg_core_if_t *core_if)
 This function returns the OTG Interrupt register.
+static uint32_t dwc_otg_read_dev_all_in_ep_intr (dwc_otg_core_if_t *core_if)
 This function reads the Device All Endpoints Interrupt register and returns the IN endpoint interrupt bits.
+static uint32_t dwc_otg_read_dev_all_out_ep_intr (dwc_otg_core_if_t *core_if)
 This function reads the Device All Endpoints Interrupt register and returns the OUT endpoint interrupt bits.
+static uint32_t dwc_otg_read_dev_in_ep_intr (dwc_otg_core_if_t *core_if, dwc_ep_t *ep)
 This function returns the Device IN EP Interrupt register.
+static uint32_t dwc_otg_read_dev_out_ep_intr (dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep)
 This function returns the Device OUT EP Interrupt register.
+static uint32_t dwc_otg_read_host_all_channels_intr (dwc_otg_core_if_t *_core_if)
 This function returns the Host All Channel Interrupt register.
+static uint32_t dwc_otg_read_host_channel_intr (dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc)
static uint32_t dwc_otg_mode (dwc_otg_core_if_t *_core_if)
 This function returns the mode of the operation, host or device.

Defines

+#define __DWC_CIL_H__
+#define OTG_CORE_REV_2_60a   0x4F54260A
 Macros defined for DWC OTG HW Release verison.
+#define OTG_CORE_REV_2_71a   0x4F54271A
+#define OTG_CORE_REV_2_72a   0x4F54272A
+#define OTG_CORE_REV_2_80a   0x4F54280A
+#define OTG_CORE_REV_2_81a   0x4F54281A
+#define OTG_CORE_REV_2_90a   0x4F54290A
+#define DWC_OTG_EP_TYPE_CONTROL   0
+#define DWC_OTG_EP_TYPE_ISOC   1
+#define DWC_OTG_EP_TYPE_BULK   2
+#define DWC_OTG_EP_TYPE_INTR   3
+#define DWC_OTG_EP_SPEED_LOW   0
+#define DWC_OTG_EP_SPEED_FULL   1
+#define DWC_OTG_EP_SPEED_HIGH   2
+#define DWC_OTG_HC_PID_DATA0   0
+#define DWC_OTG_HC_PID_DATA2   1
+#define DWC_OTG_HC_PID_DATA1   2
+#define DWC_OTG_HC_PID_MDATA   3
+#define DWC_OTG_HC_PID_SETUP   3
+#define DWC_OTG_PCGCCTL_OFFSET   0xE00
+#define DWC_OTG_DATA_FIFO_OFFSET   0x1000
+#define DWC_OTG_DATA_FIFO_SIZE   0x1000
+#define A_HOST   (1)
 A-Device is a_host.
+#define A_SUSPEND   (2)
 A-Device is a_suspend.
+#define A_PERIPHERAL   (3)
 A-Device is a_peripherial.
+#define B_PERIPHERAL   (4)
 B-Device is operating as a Peripheral.
+#define B_HOST   (5)
 B-Device is operating as a Host.

Typedefs

+typedef iso_pkt_info iso_pkt_info_t
 Information for each ISOC packet.
typedef dwc_ep dwc_ep_t
 The dwc_ep structure represents the state of a single endpoint when acting in device mode.
+typedef enum dwc_otg_halt_status dwc_otg_halt_status_e
typedef dwc_hc dwc_hc_t
 Host channel descriptor.
typedef dwc_otg_core_params dwc_otg_core_params_t
 The following parameters may be specified when starting the module.
+typedef enum dwc_otg_lx_state dwc_otg_lx_state_e
typedef dwc_otg_cil_callbacks dwc_otg_cil_callbacks_t
 DWC_otg CIL callback structure.

Enumerations

enum  dwc_otg_halt_status {
+  DWC_OTG_HC_XFER_NO_HALT_STATUS, +DWC_OTG_HC_XFER_COMPLETE, +DWC_OTG_HC_XFER_URB_COMPLETE, +DWC_OTG_HC_XFER_ACK, +
+  DWC_OTG_HC_XFER_NAK, +DWC_OTG_HC_XFER_NYET, +DWC_OTG_HC_XFER_STALL, +DWC_OTG_HC_XFER_XACT_ERR, +
+  DWC_OTG_HC_XFER_FRAME_OVERRUN, +DWC_OTG_HC_XFER_BABBLE_ERR, +DWC_OTG_HC_XFER_DATA_TOGGLE_ERR, +DWC_OTG_HC_XFER_AHB_ERR, +
+  DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE, +DWC_OTG_HC_XFER_URB_DEQUEUE +
+ }
enum  dwc_otg_lx_state { DWC_OTG_L0, +DWC_OTG_L1, +DWC_OTG_L2, +DWC_OTG_L3 + }

Functions

+void w_conn_id_status_change (void *p)
void w_wakeup_detected (void *p)
void dwc_otg_core_host_init (dwc_otg_core_if_t *_core_if)
 This function initializes the DWC_otg controller registers for host mode.
void dwc_otg_core_dev_init (dwc_otg_core_if_t *_core_if)
 This function initializes the DWC_otg controller registers for device mode.
void dwc_otg_cil_register_pcd_callbacks (dwc_otg_core_if_t *_core_if, dwc_otg_cil_callbacks_t *_cb, void *_p)
 Register PCD callbacks.
void dwc_otg_cil_register_hcd_callbacks (dwc_otg_core_if_t *_core_if, dwc_otg_cil_callbacks_t *_cb, void *_p)
 Register HCD callbacks.
+


Detailed Description

+This file contains the interface to the Core Interface Layer. +

+ +

+Definition in file dwc_otg_cil.h.


Define Documentation

+ +
+
+ + + + + + + + + + + + +
#define clear_hc_int (_hc_regs_,
_intr_   ) 
+
+
+ +

+Value:

do { \
+        hcint_data_t hcint_clear = {.d32 = 0}; \
+        hcint_clear.b._intr_ = 1; \
+        dwc_write_reg32(&(_hc_regs_)->hcint, hcint_clear.d32); \
+} while (0)
+
+

+Definition at line 903 of file dwc_otg_cil.h. +

+

+ +

+
+ + + + + + + + + + + + +
#define disable_hc_int (_hc_regs_,
_intr_   ) 
+
+
+ +

+Value:

do { \
+        hcintmsk_data_t hcintmsk = {.d32 = 0}; \
+        hcintmsk.b._intr_ = 1; \
+        dwc_modify_reg32(&(_hc_regs_)->hcintmsk, hcintmsk.d32, 0); \
+} while (0)
+
+

+Definition at line 917 of file dwc_otg_cil.h. +

+

+


Typedef Documentation

+ +
+
+ + + + +
typedef struct dwc_ep dwc_ep_t
+
+
+ +

+The dwc_ep structure represents the state of a single endpoint when acting in device mode. +

+It contains the data items needed for an endpoint to be activated and transfer packets. +

+

+ +

+
+ + + + +
typedef struct dwc_hc dwc_hc_t
+
+
+ +

+Host channel descriptor. +

+This structure represents the state of a single host channel when acting in host mode. It contains the data items needed to transfer packets to an endpoint via a host channel. +

+

+ +

+
+ + + + +
typedef struct dwc_otg_core_params dwc_otg_core_params_t
+
+
+ +

+The following parameters may be specified when starting the module. +

+These parameters define how the DWC_otg controller should be configured. +

+

+ +

+ +
+ +

+DWC_otg CIL callback structure. +

+This structure allows the HCD and PCD to register functions used for starting and stopping the PCD and HCD for role change on for a DRD. +

+

+


Enumeration Type Documentation

+ +
+
+ + + + +
enum dwc_otg_lx_state
+
+
+ +

+

Enumerator:
+ + + + + +
DWC_OTG_L0  +On state.
DWC_OTG_L1  +LPM sleep state.
DWC_OTG_L2  +USB suspend state.
DWC_OTG_L3  +Off state.
+
+ +

+Definition at line 664 of file dwc_otg_cil.h. +

+

+


Function Documentation

+ +
+
+ + + + + + + + + +
void w_wakeup_detected (void *  p  ) 
+
+
+ +

+ +

+Definition at line 473 of file dwc_otg_cil_intr.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_core_host_init (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function initializes the DWC_otg controller registers for host mode. +

+This function flushes the Tx and Rx FIFOs and it flushes any entries in the request queues. Host channels are reset to ensure that they are ready for performing transfers.

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller
+
+ +

+Definition at line 1196 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_core_dev_init (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function initializes the DWC_otg controller registers for device mode. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller
+
+ +

+Set Periodic Tx FIFO Mask all bits 0

+Set Tx FIFO Mask all bits 0

+

Todo:
NGS: Fix Periodic FIFO Sizing!
+

+

Todo:
Finish debug of this
+

+

Todo:
    +
  • if the condition needed to be checked or in any case all pending interrutps should be cleared?
+
+ +

+Definition at line 843 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_read_setup_packet (dwc_otg_core_if_t core_if,
uint32_t *  dest 
)
+
+
+ +

+This function reads a setup packet from the Rx FIFO into the destination buffer. +

+This function is called from the Rx Status Queue Level (RxStsQLvl) Interrupt routine when a SETUP packet has been received in Slave mode.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
dest Destination buffer for packet data.
+
+ +

+Definition at line 2199 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
uint32_t dwc_otg_get_frame_number (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+Gets the current USB frame number. +

+This is the frame number from the last SOF packet. +

+Definition at line 2182 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_ep0_activate (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function enables EP0 OUT to receive SETUP packets and configures EP0 IN for transmitting packets. +

+It is normally called when the "Enumeration Done" interrupt occurs.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP0 data.
+
+ +

+Definition at line 2216 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_ep_activate (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function activates an EP. +

+The Device EP control register for the EP is configured as defined in the ep structure. Note: This function is not used for EP0.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to activate.
+
+ +

+Definition at line 2268 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_ep_deactivate (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function deactivates an EP. +

+This is done by clearing the USB Active EP bit in the Device EP control register. Note: This function is not used for EP0. EP0 cannot be deactivated.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to deactivate.
+
+ +

+Definition at line 2367 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_ep_start_transfer (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function does the setup for a data transfer for an EP and starts the transfer. +

+For an IN transfer, the packets will be loaded into the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are unloaded from the Rx FIFO in the ISR. the ISR.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to start the transfer on.
+
+ +

+DIEPDMAn Register write

+Enable the Non-Periodic Tx FIFO empty interrupt, or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode, the data will be written into the fifo by the ISR.

+DOEPDMAn Register write +

+Definition at line 2475 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_ep_start_zl_transfer (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function setup a zero length transfer in Buffer DMA and Slave modes for usb requests with zero field set. +

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to start the transfer on.
+
+ +

+Enable the Non-Periodic Tx FIFO empty interrupt, or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode, the data will be written into the fifo by the ISR. +

+Definition at line 2678 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_ep0_start_transfer (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function does the setup for a data transfer for EP0 and starts the transfer. +

+For an IN transfer, the packets will be loaded into the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are unloaded from the Rx FIFO in the ISR.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP0 data.
+
+ +

+DMA Descriptor Setup

+DIEPDMA0 Register write

+Enable the Non-Periodic Tx FIFO empty interrupt, the data will be written into the fifo by the ISR.

+DMA Descriptor Setup

+DOEPDMA0 Register write +

+Definition at line 2785 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_ep0_continue_transfer (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function continues control IN transfers started by dwc_otg_ep0_start_transfer, when the transfer does not fit in a single packet. +

+NOTE: The DIEPCTL0/DOEPCTL0 registers only have one bit for the packet count.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP0 data.
+
+ +

+

Todo:
Should there be check for room in the Tx Status Queue. If not remove the code above this comment.
+

+DMA Descriptor Setup

+DIEPDMA0 Register write

+Enable the Non-Periodic Tx FIFO empty interrupt, the data will be written into the fifo by the ISR.

+DMA Descriptor Setup

+DOEPDMA0 Register write +

+Definition at line 2969 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_ep_write_packet (dwc_otg_core_if_t core_if,
dwc_ep_t ep,
int  dma 
)
+
+
+ +

+This function writes a packet into the Tx FIFO associated with the EP. +

+For non-periodic EPs the non-periodic Tx FIFO is written. For periodic EPs the periodic Tx FIFO associated with the EP is written with all packets for the next micro-frame.

+

Parameters:
+ + + + +
core_if Programming view of DWC_otg controller.
ep The EP to write packet for.
dma Indicates if DMA is being used.
+
+ +

+The buffer is padded to DWORD on a per packet basis in slave/dma mode if the MPS is not DWORD aligned. The last packet, if short, is also padded to a multiple of DWORD.

+ep->xfer_buff always starts DWORD aligned in memory and is a multiple of DWORD in length

+ep->xfer_len can be any number of bytes

+ep->xfer_count is a multiple of ep->maxpacket until the last packet

+FIFO access is DWORD

+

Todo:
NGS Where are the Periodic Tx FIFO addresses intialized? What should this be?
+ +

+Definition at line 3165 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_ep_set_stall (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+Set the EP STALL. +

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to set the stall on.
+
+ +

+Definition at line 3236 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_ep_clear_stall (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+Clear the EP STALL. +

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to clear stall from.
+
+ +

+Definition at line 3274 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_enable_device_interrupts (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function enables the Device mode interrupts. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller
+
+ +

+

Todo:
NGS: Should this be a module parameter?
+ +

+Definition at line 772 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_iso_ep_start_frm_transfer (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function initializes a descriptor chain for Isochronous transfer. +

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to start the transfer on.
+
+ +

+Enable endpoint, clear nak +

+Definition at line 3864 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_iso_ep_start_buf_transfer (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function initializes a descriptor chain for Isochronous transfer. +

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to start the transfer on.
+
+ +

+Enable endpoint, clear nak +

+Definition at line 517 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hc_init (dwc_otg_core_if_t core_if,
dwc_hc_t hc 
)
+
+
+ +

+Prepares a host channel for transferring packets to/from a specific endpoint. +

+The HCCHARn register is set up with the characteristics specified in _hc. Host channel interrupts that may need to be serviced while this transfer is in progress are enabled.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller
hc Information needed to initialize the host channel
+
+ +

+Definition at line 1352 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_hc_halt (dwc_otg_core_if_t core_if,
dwc_hc_t hc,
dwc_otg_halt_status_e  halt_status 
)
+
+
+ +

+Attempts to halt a host channel. +

+This function should only be called in Slave mode or to abort a transfer in either Slave mode or DMA mode. Under normal circumstances in DMA mode, the controller halts the channel when the transfer is complete or a condition occurs that requires application intervention.

+In slave mode, checks for a free request queue entry, then sets the Channel Enable and Channel Disable bits of the Host Channel Characteristics register of the specified channel to intiate the halt. If there is no free request queue entry, sets only the Channel Disable bit of the HCCHARn register to flush requests for this channel. In the latter case, sets a flag to indicate that the host channel needs to be halted when a request queue slot is open.

+In DMA mode, always sets the Channel Enable and Channel Disable bits of the HCCHARn register. The controller ensures there is space in the request queue before submitting the halt request.

+Some time may elapse before the core flushes any posted requests for this host channel and halts. The Channel Halted interrupt handler completes the deactivation of the host channel.

+

Parameters:
+ + + + +
core_if Controller register interface.
hc Host channel to halt.
halt_status Reason for halting the channel.
+
+ +

+Definition at line 1540 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hc_cleanup (dwc_otg_core_if_t core_if,
dwc_hc_t hc 
)
+
+
+ +

+Clears the transfer state for a host channel. +

+This function is normally called after a transfer is done and the host channel is being released.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
hc Identifies the host channel to clean up.
+
+ +

+Definition at line 1667 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hc_start_transfer (dwc_otg_core_if_t core_if,
dwc_hc_t hc 
)
+
+
+ +

+This function does the setup for a data transfer for a host channel and starts the transfer. +

+May be called in either Slave mode or DMA mode. In Slave mode, the caller must ensure that there is sufficient space in the request queue and Tx Data FIFO.

+For an OUT transfer in Slave mode, it loads a data packet into the appropriate FIFO. If necessary, additional data packets will be loaded in the Host ISR.

+For an IN transfer in Slave mode, a data packet is requested. The data packets are unloaded from the Rx FIFO in the Host ISR. If necessary, additional data packets are requested in the Host ISR.

+For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ register along with a packet count of 1 and the channel is enabled. This causes a single PING transaction to occur. Other fields in HCTSIZ are simply set to 0 since no data transfer occurs in this case.

+For a PING transfer in DMA mode, the HCTSIZ register is initialized with all the information required to perform the subsequent data transfer. In addition, the Do Ping bit is set in the HCTSIZ register. In this case, the controller performs the entire PING protocol, then starts the data transfer.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
hc Information needed to initialize the host channel. The xfer_len value may be reduced to accommodate the max widths of the XferSize and PktCnt fields in the HCTSIZn register. The multi_count value may be changed to reflect the final xfer_len value.
+
+ +

+Definition at line 1800 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_hc_continue_transfer (dwc_otg_core_if_t core_if,
dwc_hc_t hc 
)
+
+
+ +

+This function continues a data transfer that was started by previous call to dwc_otg_hc_start_transfer. +

+The caller must ensure there is sufficient space in the request queue and Tx Data FIFO. This function should only be called in Slave mode. In DMA mode, the controller acts autonomously to complete transfers programmed to a host channel.

+For an OUT transfer, a new data packet is loaded into the appropriate FIFO if there is any data remaining to be queued. For an IN transfer, another data packet is always requested. For the SETUP phase of a control transfer, this function does nothing.

+

Returns:
1 if a new request is queued, 0 if no more requests are required for this transfer.
+ +

+Definition at line 2048 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hc_do_ping (dwc_otg_core_if_t core_if,
dwc_hc_t hc 
)
+
+
+ +

+Starts a PING transfer. +

+This function should only be called in Slave mode. The Do Ping bit is set in the HCTSIZ register, then the channel is enabled. +

+Definition at line 2110 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_enable_host_interrupts (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function enables the Host mode interrupts. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller
+
+ +

+Definition at line 1130 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_disable_host_interrupts (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function disables the Host Mode interrupts. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller
+
+ +

+Definition at line 1165 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hc_start_transfer_ddma (dwc_otg_core_if_t core_if,
dwc_hc_t hc 
)
+
+
+ +

+This function does the setup for a data transfer for a host channel and starts the transfer in Descriptor DMA mode. +

+Initializes HCTSIZ register. For a PING transfer the Do Ping bit is set. Sets PID and NTD values. For periodic transfers initializes SCHED_INFO field with micro-frame bitmap.

+Initializes HCDMA register with descriptor list address and CTD value then starts the transfer via enabling the channel.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
hc Information needed to initialize the host channel.
+
+ +

+Definition at line 1968 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
static uint32_t dwc_otg_read_hprt0 (dwc_otg_core_if_t _core_if  )  [inline, static]
+
+
+ +

+This function Reads HPRT0 in preparation to modify. +

+It keeps the WC bits 0 so that if they are read as 1, they won't clear when you write it back +

+Definition at line 929 of file dwc_otg_cil.h. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_read_packet (dwc_otg_core_if_t core_if,
uint8_t *  dest,
uint16_t  bytes 
)
+
+
+ +

+This function reads a packet from the Rx FIFO into the destination buffer. +

+To read SETUP data use dwc_otg_read_setup_packet.

+

Parameters:
+ + + + +
core_if Programming view of DWC_otg controller.
dest Destination buffer for the packet.
bytes Number of bytes to copy to the destination.
+
+ +

+

Todo:
Account for the case where _dest is not dword aligned. This requires reading data from the FIFO into a uint32_t temp buffer, then moving it into the data buffer.
+ +

+Definition at line 3317 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_flush_tx_fifo (dwc_otg_core_if_t core_if,
const int  num 
)
+
+
+ +

+Flush a Tx FIFO. +

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
num Tx FIFO to flush.
+
+ +

+Definition at line 3662 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_flush_rx_fifo (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+Flush Rx FIFO. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 3694 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_core_reset (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+Do core a soft reset of the core. +

+Be careful with this because it resets all the internal state machines of the core. +

+Definition at line 3725 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
static uint32_t dwc_otg_mode (dwc_otg_core_if_t _core_if  )  [inline, static]
+
+
+ +

+This function returns the mode of the operation, host or device. +

+

Returns:
0 - Device Mode, 1 - Host Mode
+ +

+Definition at line 1097 of file dwc_otg_cil.h. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_cil_register_pcd_callbacks (dwc_otg_core_if_t core_if,
dwc_otg_cil_callbacks_t cb,
void *  p 
)
+
+
+ +

+Register PCD callbacks. +

+The callbacks are used to start and stop the PCD for interrupt processing.

+

Parameters:
+ + + + +
core_if Programming view of DWC_otg controller.
cb the PCD callback structure.
p pointer to be passed to callback function (pcd*).
+
+ +

+Definition at line 3796 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_cil_register_hcd_callbacks (dwc_otg_core_if_t core_if,
dwc_otg_cil_callbacks_t cb,
void *  p 
)
+
+
+ +

+Register HCD callbacks. +

+The callbacks are used to start and stop the HCD for interrupt processing.

+

Parameters:
+ + + + +
core_if Programming view of DWC_otg controller.
cb the HCD callback structure.
p pointer to be passed to callback function (usb_hcd*).
+
+ +

+Definition at line 3781 of file dwc_otg_cil.c. +

+

+


Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil__intr_8c-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil__intr_8c-source.html new file mode 100644 index 000000000000..e4b698882176 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil__intr_8c-source.html @@ -0,0 +1,742 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_cil_intr.c Source File + + + + + + +

dwc_otg_cil_intr.c

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil_intr.c $
+00003  * $Revision: #15 $
+00004  * $Date: 2009/04/15 $
+00005  * $Change: 1234129 $
+00006  *
+00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009  * otherwise expressly agreed to in writing between Synopsys and you.
+00010  *
+00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012  * any End User Software License Agreement or Agreement for Licensed Product
+00013  * with Synopsys or any supplement thereto. You are permitted to use and
+00014  * redistribute this Software in source and binary forms, with or without
+00015  * modification, provided that redistributions of source code must retain this
+00016  * notice. You may not view, use, disclose, copy or distribute this file or
+00017  * any information contained herein except pursuant to this license grant from
+00018  * Synopsys. If you do not agree with this notice, including the disclaimer
+00019  * below, then you are not authorized to use the Software.
+00020  *
+00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031  * DAMAGE.
+00032  * ========================================================================== */
+00033 
+00042 #include "dwc_os.h"
+00043 #include "dwc_otg_regs.h"
+00044 #include "dwc_otg_cil.h"
+00045 
+00046 #ifdef DEBUG
+00047 inline const char *op_state_str(dwc_otg_core_if_t * core_if)
+00048 {
+00049         return (core_if->op_state == A_HOST ? "a_host" :
+00050                 (core_if->op_state == A_SUSPEND ? "a_suspend" :
+00051                  (core_if->op_state == A_PERIPHERAL ? "a_peripheral" :
+00052                   (core_if->op_state == B_PERIPHERAL ? "b_peripheral" :
+00053                    (core_if->op_state == B_HOST ? "b_host" : "unknown")))));
+00054 }
+00055 #endif
+00056 
+00061 int32_t dwc_otg_handle_mode_mismatch_intr(dwc_otg_core_if_t * core_if)
+00062 {
+00063         gintsts_data_t gintsts;
+00064         DWC_WARN("Mode Mismatch Interrupt: currently in %s mode\n",
+00065                  dwc_otg_mode(core_if) ? "Host" : "Device");
+00066 
+00067         /* Clear interrupt */
+00068         gintsts.d32 = 0;
+00069         gintsts.b.modemismatch = 1;
+00070         dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
+00071         return 1;
+00072 }
+00073 
+00078 static inline void hcd_start(dwc_otg_core_if_t * core_if)
+00079 {
+00080         if (core_if->hcd_cb && core_if->hcd_cb->start) {
+00081                 core_if->hcd_cb->start(core_if->hcd_cb->p);
+00082         }
+00083 }
+00084 
+00089 static inline void hcd_stop(dwc_otg_core_if_t * core_if)
+00090 {
+00091         if (core_if->hcd_cb && core_if->hcd_cb->stop) {
+00092                 core_if->hcd_cb->stop(core_if->hcd_cb->p);
+00093         }
+00094 }
+00095 
+00100 static inline void hcd_disconnect(dwc_otg_core_if_t * core_if)
+00101 {
+00102         if (core_if->hcd_cb && core_if->hcd_cb->disconnect) {
+00103                 core_if->hcd_cb->disconnect(core_if->hcd_cb->p);
+00104         }
+00105 }
+00106 
+00112 static inline void hcd_session_start(dwc_otg_core_if_t * core_if)
+00113 {
+00114         if (core_if->hcd_cb && core_if->hcd_cb->session_start) {
+00115                 core_if->hcd_cb->session_start(core_if->hcd_cb->p);
+00116         }
+00117 }
+00118 
+00119 #ifdef CONFIG_USB_DWC_OTG_LPM
+00120 
+00126 static inline void hcd_sleep(dwc_otg_core_if_t * core_if)
+00127 {
+00128         if (core_if->hcd_cb && core_if->hcd_cb->sleep) {
+00129                 core_if->hcd_cb->sleep(core_if->hcd_cb->p);
+00130         }
+00131 }
+00132 #endif
+00133 
+00138 static inline void hcd_resume(dwc_otg_core_if_t * core_if)
+00139 {
+00140         if (core_if->hcd_cb && core_if->hcd_cb->resume_wakeup) {
+00141                 core_if->hcd_cb->resume_wakeup(core_if->hcd_cb->p);
+00142         }
+00143 }
+00144 
+00149 static inline void pcd_start(dwc_otg_core_if_t * core_if)
+00150 {
+00151         if (core_if->pcd_cb && core_if->pcd_cb->start) {
+00152                 core_if->pcd_cb->start(core_if->pcd_cb->p);
+00153         }
+00154 }
+00155 
+00160 static inline void pcd_stop(dwc_otg_core_if_t * core_if)
+00161 {
+00162         if (core_if->pcd_cb && core_if->pcd_cb->stop) {
+00163                 core_if->pcd_cb->stop(core_if->pcd_cb->p);
+00164         }
+00165 }
+00166 
+00171 static inline void pcd_suspend(dwc_otg_core_if_t * core_if)
+00172 {
+00173         if (core_if->pcd_cb && core_if->pcd_cb->suspend) {
+00174                 core_if->pcd_cb->suspend(core_if->pcd_cb->p);
+00175         }
+00176 }
+00177 
+00182 static inline void pcd_resume(dwc_otg_core_if_t * core_if)
+00183 {
+00184         if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
+00185                 core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
+00186         }
+00187 }
+00188 
+00196 int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t * core_if)
+00197 {
+00198         dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+00199         gotgint_data_t gotgint;
+00200         gotgctl_data_t gotgctl;
+00201         gintmsk_data_t gintmsk;
+00202 
+00203         gotgint.d32 = dwc_read_reg32(&global_regs->gotgint);
+00204         gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
+00205         DWC_DEBUGPL(DBG_CIL, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint.d32,
+00206                     op_state_str(core_if));
+00207 
+00208         if (gotgint.b.sesenddet) {
+00209                 DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
+00210                             "Session End Detected++ (%s)\n",
+00211                             op_state_str(core_if));
+00212                 gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
+00213 
+00214                 if (core_if->op_state == B_HOST) {
+00215                         pcd_start(core_if);
+00216                         core_if->op_state = B_PERIPHERAL;
+00217                 } else {
+00218                         /* If not B_HOST and Device HNP still set. HNP
+00219                          * Did not succeed!*/
+00220                         if (gotgctl.b.devhnpen) {
+00221                                 DWC_DEBUGPL(DBG_ANY, "Session End Detected\n");
+00222                                 __DWC_ERROR("Device Not Connected/Responding!\n");
+00223                         }
+00224 
+00225                         /* If Session End Detected the B-Cable has
+00226                          * been disconnected. */
+00227                         /* Reset PCD and Gadget driver to a
+00228                          * clean state. */
+00229                         core_if->lx_state = DWC_OTG_L0;
+00230                         pcd_stop(core_if);
+00231                 }
+00232                 gotgctl.d32 = 0;
+00233                 gotgctl.b.devhnpen = 1;
+00234                 dwc_modify_reg32(&global_regs->gotgctl, gotgctl.d32, 0);
+00235         }
+00236         if (gotgint.b.sesreqsucstschng) {
+00237                 DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
+00238                             "Session Reqeust Success Status Change++\n");
+00239                 gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
+00240                 if (gotgctl.b.sesreqscs) {
+00241                         if ((core_if->core_params->phy_type ==
+00242                              DWC_PHY_TYPE_PARAM_FS) && (core_if->core_params->i2c_enable)) {
+00243                                 core_if->srp_success = 1;
+00244                         } else {
+00245                                 pcd_resume(core_if);
+00246                                 /* Clear Session Request */
+00247                                 gotgctl.d32 = 0;
+00248                                 gotgctl.b.sesreq = 1;
+00249                                 dwc_modify_reg32(&global_regs->gotgctl,
+00250                                                  gotgctl.d32, 0);
+00251                         }
+00252                 }
+00253         }
+00254         if (gotgint.b.hstnegsucstschng) {
+00255                 /* Print statements during the HNP interrupt handling
+00256                  * can cause it to fail.*/
+00257                 gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
+00258                 if (gotgctl.b.hstnegscs) {
+00259                         if (dwc_otg_is_host_mode(core_if)) {
+00260                                 core_if->op_state = B_HOST;
+00261                                 /*
+00262                                  * Need to disable SOF interrupt immediately.
+00263                                  * When switching from device to host, the PCD
+00264                                  * interrupt handler won't handle the
+00265                                  * interrupt if host mode is already set. The
+00266                                  * HCD interrupt handler won't get called if
+00267                                  * the HCD state is HALT. This means that the
+00268                                  * interrupt does not get handled and Linux
+00269                                  * complains loudly.
+00270                                  */
+00271                                 gintmsk.d32 = 0;
+00272                                 gintmsk.b.sofintr = 1;
+00273                                 dwc_modify_reg32(&global_regs->gintmsk,
+00274                                                  gintmsk.d32, 0);
+00275                                 pcd_stop(core_if);
+00276                                 /*
+00277                                  * Initialize the Core for Host mode.
+00278                                  */
+00279                                 hcd_start(core_if);
+00280                                 core_if->op_state = B_HOST;
+00281                         }
+00282                 } else {
+00283                         gotgctl.d32 = 0;
+00284                         gotgctl.b.hnpreq = 1;
+00285                         gotgctl.b.devhnpen = 1;
+00286                         dwc_modify_reg32(&global_regs->gotgctl, gotgctl.d32, 0);
+00287                         DWC_DEBUGPL(DBG_ANY, "HNP Failed\n");
+00288                         __DWC_ERROR("Device Not Connected/Responding\n");
+00289                 }
+00290         }
+00291         if (gotgint.b.hstnegdet) {
+00292                 /* The disconnect interrupt is set at the same time as
+00293                  * Host Negotiation Detected.  During the mode
+00294                  * switch all interrupts are cleared so the disconnect
+00295                  * interrupt handler will not get executed.
+00296                  */
+00297                 DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
+00298                             "Host Negotiation Detected++ (%s)\n",
+00299                             (dwc_otg_is_host_mode(core_if) ? "Host" :
+00300                              "Device"));
+00301                 if (dwc_otg_is_device_mode(core_if)) {
+00302                         DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n",
+00303                                     core_if->op_state);
+00304                         hcd_disconnect(core_if);
+00305                         pcd_start(core_if);
+00306                         core_if->op_state = A_PERIPHERAL;
+00307                 } else {
+00308                         /*
+00309                          * Need to disable SOF interrupt immediately. When
+00310                          * switching from device to host, the PCD interrupt
+00311                          * handler won't handle the interrupt if host mode is
+00312                          * already set. The HCD interrupt handler won't get
+00313                          * called if the HCD state is HALT. This means that
+00314                          * the interrupt does not get handled and Linux
+00315                          * complains loudly.
+00316                          */
+00317                         gintmsk.d32 = 0;
+00318                         gintmsk.b.sofintr = 1;
+00319                         dwc_modify_reg32(&global_regs->gintmsk, gintmsk.d32, 0);
+00320                         pcd_stop(core_if);
+00321                         hcd_start(core_if);
+00322                         core_if->op_state = A_HOST;
+00323                 }
+00324         }
+00325         if (gotgint.b.adevtoutchng) {
+00326                 DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
+00327                             "A-Device Timeout Change++\n");
+00328         }
+00329         if (gotgint.b.debdone) {
+00330                 DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " "Debounce Done++\n");
+00331         }
+00332 
+00333         /* Clear GOTGINT */
+00334         dwc_write_reg32(&core_if->core_global_regs->gotgint, gotgint.d32);
+00335 
+00336         return 1;
+00337 }
+00338 
+00339 void w_conn_id_status_change(void *p)
+00340 {
+00341         dwc_otg_core_if_t *core_if = p;
+00342         uint32_t count = 0;
+00343         gotgctl_data_t gotgctl = {.d32 = 0 };
+00344 
+00345         gotgctl.d32 = dwc_read_reg32(&core_if->core_global_regs->gotgctl);
+00346         DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
+00347         DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);
+00348 
+00349         /* B-Device connector (Device Mode) */
+00350         if (gotgctl.b.conidsts) {
+00351                 /* Wait for switch to device mode. */
+00352                 while (!dwc_otg_is_device_mode(core_if)) {
+00353                         DWC_PRINTF("Waiting for Peripheral Mode, Mode=%s\n",
+00354                                    (dwc_otg_is_host_mode(core_if) ? "Host" :
+00355                                     "Peripheral"));
+00356                         dwc_mdelay(100);
+00357                         if (++count > 10000)
+00358                                 break;
+00359                 }
+00360                 DWC_ASSERT(++count < 10000,
+00361                            "Connection id status change timed out");
+00362                 core_if->op_state = B_PERIPHERAL;
+00363                 dwc_otg_core_init(core_if);
+00364                 dwc_otg_enable_global_interrupts(core_if);
+00365                 pcd_start(core_if);
+00366         } else {
+00367                 /* A-Device connector (Host Mode) */
+00368                 while (!dwc_otg_is_host_mode(core_if)) {
+00369                         DWC_PRINTF("Waiting for Host Mode, Mode=%s\n",
+00370                                    (dwc_otg_is_host_mode(core_if) ? "Host" :
+00371                                     "Peripheral"));
+00372                         dwc_mdelay(100);
+00373                         if (++count > 10000)
+00374                                 break;
+00375                 }
+00376                 DWC_ASSERT(++count < 10000,
+00377                            "Connection id status change timed out");
+00378                 core_if->op_state = A_HOST;
+00379                 /*
+00380                  * Initialize the Core for Host mode.
+00381                  */
+00382                 dwc_otg_core_init(core_if);
+00383                 dwc_otg_enable_global_interrupts(core_if);
+00384                 hcd_start(core_if);
+00385         }
+00386 }
+00387 
+00399 int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t * core_if)
+00400 {
+00401 
+00402         /*
+00403          * Need to disable SOF interrupt immediately. If switching from device
+00404          * to host, the PCD interrupt handler won't handle the interrupt if
+00405          * host mode is already set. The HCD interrupt handler won't get
+00406          * called if the HCD state is HALT. This means that the interrupt does
+00407          * not get handled and Linux complains loudly.
+00408          */
+00409         gintmsk_data_t gintmsk = {.d32 = 0 };
+00410         gintsts_data_t gintsts = {.d32 = 0 };
+00411 
+00412         gintmsk.b.sofintr = 1;
+00413         dwc_modify_reg32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
+00414 
+00415         DWC_DEBUGPL(DBG_CIL,
+00416                     " ++Connector ID Status Change Interrupt++  (%s)\n",
+00417                     (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"));
+00418 
+00419         /*
+00420          * Need to schedule a work, as there are possible DELAY function calls
+00421          */
+00422         DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change,
+00423                            core_if, "connection id status change");
+00424 
+00425         /* Set flag and clear interrupt */
+00426         gintsts.b.conidstschng = 1;
+00427         dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
+00428 
+00429         return 1;
+00430 }
+00431 
+00441 int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t * core_if)
+00442 {
+00443         hprt0_data_t hprt0;
+00444         gintsts_data_t gintsts;
+00445 
+00446 #ifndef DWC_HOST_ONLY
+00447         DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");
+00448 
+00449         if (dwc_otg_is_device_mode(core_if)) {
+00450                 DWC_PRINTF("SRP: Device mode\n");
+00451         } else {
+00452                 DWC_PRINTF("SRP: Host mode\n");
+00453 
+00454                 /* Turn on the port power bit. */
+00455                 hprt0.d32 = dwc_otg_read_hprt0(core_if);
+00456                 hprt0.b.prtpwr = 1;
+00457                 dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+00458 
+00459                 /* Start the Connection timer. So a message can be displayed
+00460                  * if connect does not occur within 10 seconds. */
+00461                 hcd_session_start(core_if);
+00462         }
+00463 #endif
+00464 
+00465         /* Clear interrupt */
+00466         gintsts.d32 = 0;
+00467         gintsts.b.sessreqintr = 1;
+00468         dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
+00469 
+00470         return 1;
+00471 }
+00472 
+00473 void w_wakeup_detected(void *p)
+00474 {
+00475         dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) p;
+00476         /*
+00477          * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
+00478          * so that OPT tests pass with all PHYs).
+00479          */
+00480         hprt0_data_t hprt0 = {.d32 = 0 };
+00481 #if 0
+00482         pcgcctl_data_t pcgcctl = {.d32 = 0 };
+00483         /* Restart the Phy Clock */
+00484         pcgcctl.b.stoppclk = 1;
+00485         dwc_modify_reg32(core_if->pcgcctl, pcgcctl.d32, 0);
+00486         dwc_udelay(10);
+00487 #endif                          //0
+00488         hprt0.d32 = dwc_otg_read_hprt0(core_if);
+00489         DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
+00490 //      dwc_mdelay(70);
+00491         hprt0.b.prtres = 0;     /* Resume */
+00492         dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+00493         DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
+00494                     dwc_read_reg32(core_if->host_if->hprt0));
+00495 
+00496         hcd_resume(core_if);
+00497 
+00499         core_if->lx_state = DWC_OTG_L0;
+00500 
+00501 }
+00502 
+00510 int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t * core_if)
+00511 {
+00512         gintsts_data_t gintsts;
+00513 
+00514         DWC_DEBUGPL(DBG_ANY,
+00515                     "++Resume and Remote Wakeup Detected Interrupt++\n");
+00516 
+00517         DWC_PRINTF("%s lxstate = %d\n", __func__, core_if->lx_state);
+00518 
+00519         if (dwc_otg_is_device_mode(core_if)) {
+00520                 dctl_data_t dctl = {.d32 = 0 };
+00521                 DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
+00522                             dwc_read_reg32(&core_if->dev_if->dev_global_regs->
+00523                                            dsts));
+00524                 if (core_if->lx_state == DWC_OTG_L2) {
+00525 #ifdef PARTIAL_POWER_DOWN
+00526                         if (core_if->hwcfg4.b.power_optimiz) {
+00527                                 pcgcctl_data_t power = {.d32 = 0 };
+00528 
+00529                                 power.d32 = dwc_read_reg32(core_if->pcgcctl);
+00530                                 DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n",
+00531                                             power.d32);
+00532 
+00533                                 power.b.stoppclk = 0;
+00534                                 dwc_write_reg32(core_if->pcgcctl, power.d32);
+00535 
+00536                                 power.b.pwrclmp = 0;
+00537                                 dwc_write_reg32(core_if->pcgcctl, power.d32);
+00538 
+00539                                 power.b.rstpdwnmodule = 0;
+00540                                 dwc_write_reg32(core_if->pcgcctl, power.d32);
+00541                         }
+00542 #endif
+00543                         /* Clear the Remote Wakeup Signalling */
+00544                         dctl.b.rmtwkupsig = 1;
+00545                         dwc_modify_reg32(&core_if->dev_if->dev_global_regs->
+00546                                          dctl, dctl.d32, 0);
+00547 
+00548                         if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
+00549                                 core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->
+00550                                                                p);
+00551                         }
+00552                 } else {
+00553                         glpmcfg_data_t lpmcfg;
+00554                         lpmcfg.d32 =
+00555                             dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
+00556                         lpmcfg.b.hird_thres &= (~(1 << 4));
+00557                         dwc_write_reg32(&core_if->core_global_regs->glpmcfg,
+00558                                         lpmcfg.d32);
+00559                 }
+00561                 core_if->lx_state = DWC_OTG_L0;
+00562         } else {
+00563                 if (core_if->lx_state != DWC_OTG_L1) {
+00564                         pcgcctl_data_t pcgcctl = {.d32 = 0 };
+00565 
+00566                         /* Restart the Phy Clock */
+00567                         pcgcctl.b.stoppclk = 1;
+00568                         dwc_modify_reg32(core_if->pcgcctl, pcgcctl.d32, 0);
+00569 
+00570                         DWC_TIMER_SCHEDULE(core_if->wkp_timer, 71);
+00571                 } else {
+00573                         core_if->lx_state = DWC_OTG_L0;
+00574                 }
+00575         }
+00576 
+00577         /* Clear interrupt */
+00578         gintsts.d32 = 0;
+00579         gintsts.b.wkupintr = 1;
+00580         dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
+00581 
+00582         return 1;
+00583 }
+00584 
+00589 int32_t dwc_otg_handle_disconnect_intr(dwc_otg_core_if_t * core_if)
+00590 {
+00591         gintsts_data_t gintsts;
+00592 
+00593         DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n",
+00594                     (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"),
+00595                     op_state_str(core_if));
+00596 
+00598 #ifndef DWC_HOST_ONLY
+00599         if (core_if->op_state == B_HOST) {
+00600                 /* If in device mode Disconnect and stop the HCD, then
+00601                  * start the PCD. */
+00602                 hcd_disconnect(core_if);
+00603                 pcd_start(core_if);
+00604                 core_if->op_state = B_PERIPHERAL;
+00605         } else if (dwc_otg_is_device_mode(core_if)) {
+00606                 gotgctl_data_t gotgctl = {.d32 = 0 };
+00607                 gotgctl.d32 =
+00608                     dwc_read_reg32(&core_if->core_global_regs->gotgctl);
+00609                 if (gotgctl.b.hstsethnpen == 1) {
+00610                         /* Do nothing, if HNP in process the OTG
+00611                          * interrupt "Host Negotiation Detected"
+00612                          * interrupt will do the mode switch.
+00613                          */
+00614                 } else if (gotgctl.b.devhnpen == 0) {
+00615                         /* If in device mode Disconnect and stop the HCD, then
+00616                          * start the PCD. */
+00617                         hcd_disconnect(core_if);
+00618                         pcd_start(core_if);
+00619                         core_if->op_state = B_PERIPHERAL;
+00620                 } else {
+00621                         DWC_DEBUGPL(DBG_ANY, "!a_peripheral && !devhnpen\n");
+00622                 }
+00623         } else {
+00624                 if (core_if->op_state == A_HOST) {
+00625                         /* A-Cable still connected but device disconnected. */
+00626                         hcd_disconnect(core_if);
+00627                 }
+00628         }
+00629 #endif
+00630         /* Change to L3(OFF) state */
+00631         core_if->lx_state = DWC_OTG_L3;
+00632 
+00633         gintsts.d32 = 0;
+00634         gintsts.b.disconnect = 1;
+00635         dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
+00636         return 1;
+00637 }
+00638 
+00649 int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t * core_if)
+00650 {
+00651         dsts_data_t dsts;
+00652         gintsts_data_t gintsts;
+00653 
+00654         DWC_DEBUGPL(DBG_ANY, "USB SUSPEND\n");
+00655 
+00656         if (dwc_otg_is_device_mode(core_if)) {
+00657                 /* Check the Device status register to determine if the Suspend
+00658                  * state is active. */
+00659                 dsts.d32 =
+00660                     dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
+00661                 DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32);
+00662                 DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d "
+00663                             "HWCFG4.power Optimize=%d\n",
+00664                             dsts.b.suspsts, core_if->hwcfg4.b.power_optimiz);
+00665 
+00666 #ifdef PARTIAL_POWER_DOWN
+00667 
+00669                 if (dsts.b.suspsts && core_if->hwcfg4.b.power_optimiz) {
+00670                         pcgcctl_data_t power = {.d32 = 0 };
+00671                         DWC_DEBUGPL(DBG_CIL, "suspend\n");
+00672 
+00673                         power.b.pwrclmp = 1;
+00674                         dwc_write_reg32(core_if->pcgcctl, power.d32);
+00675 
+00676                         power.b.rstpdwnmodule = 1;
+00677                         dwc_modify_reg32(core_if->pcgcctl, 0, power.d32);
+00678 
+00679                         power.b.stoppclk = 1;
+00680                         dwc_modify_reg32(core_if->pcgcctl, 0, power.d32);
+00681 
+00682                 } else {
+00683                         DWC_DEBUGPL(DBG_ANY, "disconnect?\n");
+00684                 }
+00685 #endif
+00686                 /* PCD callback for suspend. */
+00687                 pcd_suspend(core_if);
+00688         } else {
+00689                 if (core_if->op_state == A_PERIPHERAL) {
+00690                         DWC_DEBUGPL(DBG_ANY, "a_peripheral->a_host\n");
+00691                         /* Clear the a_peripheral flag, back to a_host. */
+00692                         pcd_stop(core_if);
+00693                         hcd_start(core_if);
+00694                         core_if->op_state = A_HOST;
+00695                 }
+00696         }
+00697 
+00698         /* Change to L2(suspend) state */
+00699         core_if->lx_state = DWC_OTG_L2;
+00700 
+00701         /* Clear interrupt */
+00702         gintsts.d32 = 0;
+00703         gintsts.b.usbsuspend = 1;
+00704         dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
+00705 
+00706         return 1;
+00707 }
+00708 
+00709 #ifdef CONFIG_USB_DWC_OTG_LPM
+00710 
+00713 static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t * core_if)
+00714 {
+00715         glpmcfg_data_t lpmcfg;
+00716         gintsts_data_t gintsts;
+00717 
+00718         if (!core_if->core_params->lpm_enable) {
+00719                 DWC_PRINTF("Unexpected LPM interrupt\n");
+00720         }
+00721 
+00722         lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
+00723         DWC_PRINTF("LPM config register = 0x%08x\n", lpmcfg.d32);
+00724 
+00725         if (dwc_otg_is_host_mode(core_if)) {
+00726                 hcd_sleep(core_if);
+00727         } else {
+00728                 lpmcfg.b.hird_thres |= (1 << 4);
+00729                 dwc_write_reg32(&core_if->core_global_regs->glpmcfg,
+00730                                 lpmcfg.d32);
+00731         }
+00732 
+00733         /* Examine prt_sleep_sts after TL1TokenTetry period max (10 us) */      
+00734         dwc_udelay(10);
+00735         lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
+00736         if (lpmcfg.b.prt_sleep_sts) {
+00737                 /* Save the current state */
+00738                 core_if->lx_state = DWC_OTG_L1;
+00739         }
+00740 
+00741         /* Clear interrupt  */
+00742         gintsts.d32 = 0;
+00743         gintsts.b.lpmtranrcvd = 1;
+00744         dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
+00745         return 1;
+00746 }
+00747 #endif                          /* CONFIG_USB_DWC_OTG_LPM */
+00748 
+00752 static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if)
+00753 {
+00754         gintsts_data_t gintsts;
+00755         gintmsk_data_t gintmsk;
+00756         gintmsk_data_t gintmsk_common = {.d32 = 0 };
+00757         gintmsk_common.b.wkupintr = 1;
+00758         gintmsk_common.b.sessreqintr = 1;
+00759         gintmsk_common.b.conidstschng = 1;
+00760         gintmsk_common.b.otgintr = 1;
+00761         gintmsk_common.b.modemismatch = 1;
+00762         gintmsk_common.b.disconnect = 1;
+00763         gintmsk_common.b.usbsuspend = 1;
+00764 #ifdef CONFIG_USB_DWC_OTG_LPM
+00765         gintmsk_common.b.lpmtranrcvd = 1;
+00766 #endif
+00767 
+00770         gintmsk_common.b.portintr = 1;
+00771 
+00772         gintsts.d32 = dwc_read_reg32(&core_if->core_global_regs->gintsts);
+00773         gintmsk.d32 = dwc_read_reg32(&core_if->core_global_regs->gintmsk);
+00774 #ifdef DEBUG
+00775         /* if any common interrupts set */
+00776         if (gintsts.d32 & gintmsk_common.d32) {
+00777                 DWC_DEBUGPL(DBG_ANY, "gintsts=%08x  gintmsk=%08x\n",
+00778                             gintsts.d32, gintmsk.d32);
+00779         }
+00780 #endif
+00781 
+00782         return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32);
+00783 
+00784 }
+00785 
+00800 int32_t dwc_otg_handle_common_intr(dwc_otg_core_if_t * core_if)
+00801 {
+00802         int retval = 0;
+00803         gintsts_data_t gintsts;
+00804 
+00805         gintsts.d32 = dwc_otg_read_common_intr(core_if);
+00806 
+00807         if (gintsts.b.modemismatch) {
+00808                 retval |= dwc_otg_handle_mode_mismatch_intr(core_if);
+00809         }
+00810         if (gintsts.b.otgintr) {
+00811                 retval |= dwc_otg_handle_otg_intr(core_if);
+00812         }
+00813         if (gintsts.b.conidstschng) {
+00814                 retval |= dwc_otg_handle_conn_id_status_change_intr(core_if);
+00815         }
+00816         if (gintsts.b.disconnect) {
+00817                 retval |= dwc_otg_handle_disconnect_intr(core_if);
+00818         }
+00819         if (gintsts.b.sessreqintr) {
+00820                 retval |= dwc_otg_handle_session_req_intr(core_if);
+00821         }
+00822         if (gintsts.b.wkupintr) {
+00823                 retval |= dwc_otg_handle_wakeup_detected_intr(core_if);
+00824         }
+00825         if (gintsts.b.usbsuspend) {
+00826                 retval |= dwc_otg_handle_usb_suspend_intr(core_if);
+00827         }
+00828 #ifdef CONFIG_USB_DWC_OTG_LPM
+00829         if (gintsts.b.lpmtranrcvd) {
+00830                 retval |= dwc_otg_handle_lpm_intr(core_if);
+00831         }
+00832 #endif
+00833 
+00834         if (gintsts.b.portintr && dwc_otg_is_device_mode(core_if)) {
+00835                 /* The port interrupt occurs while in device mode with HPRT0
+00836                  * Port Enable/Disable.
+00837                  */
+00838                 gintsts.d32 = 0;
+00839                 gintsts.b.portintr = 1;
+00840                 dwc_write_reg32(&core_if->core_global_regs->gintsts,
+00841                                 gintsts.d32);
+00842                 retval |= 1;
+00843 
+00844         }
+00845         return retval;
+00846 }
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil__intr_8c.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil__intr_8c.html new file mode 100644 index 000000000000..24c66e38dee7 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__cil__intr_8c.html @@ -0,0 +1,645 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_cil_intr.c File Reference + + + + + + +

dwc_otg_cil_intr.c File Reference

The Core Interface Layer provides basic services for accessing and managing the DWC_otg hardware. More... +

+#include "dwc_os.h"
+#include "dwc_otg_regs.h"
+#include "dwc_otg_cil.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Functions

int32_t dwc_otg_handle_mode_mismatch_intr (dwc_otg_core_if_t *core_if)
 This function will log a debug message.
static void hcd_start (dwc_otg_core_if_t *core_if)
 Start the HCD.
static void hcd_stop (dwc_otg_core_if_t *core_if)
 Stop the HCD.
static void hcd_disconnect (dwc_otg_core_if_t *core_if)
 Disconnect the HCD.
static void hcd_session_start (dwc_otg_core_if_t *core_if)
 Inform the HCD the a New Session has begun.
static void hcd_resume (dwc_otg_core_if_t *core_if)
 Resume the HCD.
static void pcd_start (dwc_otg_core_if_t *core_if)
 Start the PCD.
static void pcd_stop (dwc_otg_core_if_t *core_if)
 Stop the PCD.
static void pcd_suspend (dwc_otg_core_if_t *core_if)
 Suspend the PCD.
static void pcd_resume (dwc_otg_core_if_t *core_if)
 Resume the PCD.
int32_t dwc_otg_handle_otg_intr (dwc_otg_core_if_t *core_if)
 This function handles the OTG Interrupts.
+void w_conn_id_status_change (void *p)
int32_t dwc_otg_handle_conn_id_status_change_intr (dwc_otg_core_if_t *core_if)
 This function handles the Connector ID Status Change Interrupt.
int32_t dwc_otg_handle_session_req_intr (dwc_otg_core_if_t *core_if)
 This interrupt indicates that a device is initiating the Session Request Protocol to request the host to turn on bus power so a new session can begin.
void w_wakeup_detected (void *p)
int32_t dwc_otg_handle_wakeup_detected_intr (dwc_otg_core_if_t *core_if)
 This interrupt indicates that the DWC_otg controller has detected a resume or remote wakeup sequence.
int32_t dwc_otg_handle_disconnect_intr (dwc_otg_core_if_t *core_if)
 This interrupt indicates that a device has been disconnected from the root port.
int32_t dwc_otg_handle_usb_suspend_intr (dwc_otg_core_if_t *core_if)
 This interrupt indicates that SUSPEND state has been detected on the USB.
static uint32_t dwc_otg_read_common_intr (dwc_otg_core_if_t *core_if)
 This function returns the Core Interrupt register.
int32_t dwc_otg_handle_common_intr (dwc_otg_core_if_t *core_if)
 This function should be called on every hardware interrupt.
+


Detailed Description

+The Core Interface Layer provides basic services for accessing and managing the DWC_otg hardware. +

+These services are used by both the Host Controller Driver and the Peripheral Controller Driver.

+This file contains the Common Interrupt handlers. +

+Definition in file dwc_otg_cil_intr.c.


Function Documentation

+ +
+
+ + + + + + + + + +
int32_t dwc_otg_handle_mode_mismatch_intr (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function will log a debug message. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 61 of file dwc_otg_cil_intr.c. +

+

+ +

+
+ + + + + + + + + +
static void hcd_start (dwc_otg_core_if_t core_if  )  [inline, static]
+
+
+ +

+Start the HCD. +

+Helper function for using the HCD callbacks.

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 78 of file dwc_otg_cil_intr.c. +

+

+ +

+
+ + + + + + + + + +
static void hcd_stop (dwc_otg_core_if_t core_if  )  [inline, static]
+
+
+ +

+Stop the HCD. +

+Helper function for using the HCD callbacks.

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 89 of file dwc_otg_cil_intr.c. +

+

+ +

+
+ + + + + + + + + +
static void hcd_disconnect (dwc_otg_core_if_t core_if  )  [inline, static]
+
+
+ +

+Disconnect the HCD. +

+Helper function for using the HCD callbacks.

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 100 of file dwc_otg_cil_intr.c. +

+

+ +

+
+ + + + + + + + + +
static void hcd_session_start (dwc_otg_core_if_t core_if  )  [inline, static]
+
+
+ +

+Inform the HCD the a New Session has begun. +

+Helper function for using the HCD callbacks.

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 112 of file dwc_otg_cil_intr.c. +

+

+ +

+
+ + + + + + + + + +
static void hcd_resume (dwc_otg_core_if_t core_if  )  [inline, static]
+
+
+ +

+Resume the HCD. +

+Helper function for using the HCD callbacks.

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 138 of file dwc_otg_cil_intr.c. +

+

+ +

+
+ + + + + + + + + +
static void pcd_start (dwc_otg_core_if_t core_if  )  [inline, static]
+
+
+ +

+Start the PCD. +

+Helper function for using the PCD callbacks.

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 149 of file dwc_otg_cil_intr.c. +

+

+ +

+
+ + + + + + + + + +
static void pcd_stop (dwc_otg_core_if_t core_if  )  [inline, static]
+
+
+ +

+Stop the PCD. +

+Helper function for using the PCD callbacks.

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 160 of file dwc_otg_cil_intr.c. +

+

+ +

+
+ + + + + + + + + +
static void pcd_suspend (dwc_otg_core_if_t core_if  )  [inline, static]
+
+
+ +

+Suspend the PCD. +

+Helper function for using the PCD callbacks.

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 171 of file dwc_otg_cil_intr.c. +

+

+ +

+
+ + + + + + + + + +
static void pcd_resume (dwc_otg_core_if_t core_if  )  [inline, static]
+
+
+ +

+Resume the PCD. +

+Helper function for using the PCD callbacks.

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 182 of file dwc_otg_cil_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_handle_otg_intr (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function handles the OTG Interrupts. +

+It reads the OTG Interrupt Register (GOTGINT) to determine what interrupt has occurred.

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 196 of file dwc_otg_cil_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_handle_conn_id_status_change_intr (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function handles the Connector ID Status Change Interrupt. +

+It reads the OTG Interrupt Register (GOTCTL) to determine whether this is a Device to Host Mode transition or a Host Mode to Device Transition.

+This only occurs when the cable is connected/removed from the PHY connector.

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 399 of file dwc_otg_cil_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_handle_session_req_intr (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This interrupt indicates that a device is initiating the Session Request Protocol to request the host to turn on bus power so a new session can begin. +

+The handler responds by turning on bus power. If the DWC_otg controller is in low power mode, the handler brings the controller out of low power mode before turning on bus power.

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 441 of file dwc_otg_cil_intr.c. +

+

+ +

+
+ + + + + + + + + +
void w_wakeup_detected (void *  p  ) 
+
+
+ +

+ +

+Definition at line 473 of file dwc_otg_cil_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_handle_wakeup_detected_intr (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This interrupt indicates that the DWC_otg controller has detected a resume or remote wakeup sequence. +

+If the DWC_otg controller is in low power mode, the handler must brings the controller out of low power mode. The controller automatically begins resume signaling. The handler schedules a time to stop resume signaling. +

+Change to L0 state

+Change to L0 state +

+Definition at line 510 of file dwc_otg_cil_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_handle_disconnect_intr (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This interrupt indicates that a device has been disconnected from the root port. +

+ +

+

Todo:
Consolidate this if statement.
+ +

+Definition at line 589 of file dwc_otg_cil_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_handle_usb_suspend_intr (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This interrupt indicates that SUSPEND state has been detected on the USB. +

+For HNP the USB Suspend interrupt signals the change from "a_peripheral" to "a_host".

+When power management is enabled the core will be put in low power mode. +

+Definition at line 649 of file dwc_otg_cil_intr.c. +

+

+ +

+
+ + + + + + + + + +
static uint32_t dwc_otg_read_common_intr (dwc_otg_core_if_t core_if  )  [inline, static]
+
+
+ +

+This function returns the Core Interrupt register. +

+ +

+

Todo:
: The port interrupt occurs while in device mode. Added code to CIL to clear the interrupt for now!
+ +

+Definition at line 752 of file dwc_otg_cil_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_handle_common_intr (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function should be called on every hardware interrupt. +

+The common interrupts are those that occur in both Host and Device mode. This handler handles the following interrupts:

    +
  • Mode Mismatch Interrupt
  • Disconnect Interrupt
  • OTG Interrupt
  • Connector ID Status Change Interrupt
  • Session Request Interrupt.
  • Resume / Remote Wakeup Detected Interrupt.
  • LPM Transaction Received Interrutp
+ +

+Definition at line 800 of file dwc_otg_cil_intr.c. +

+

+


Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__core__if_8h-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__core__if_8h-source.html new file mode 100644 index 000000000000..76294c2bf173 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__core__if_8h-source.html @@ -0,0 +1,365 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_core_if.h Source File + + + + + + +

dwc_otg_core_if.h

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_core_if.h $
+00003  * $Revision: #4 $
+00004  * $Date: 2008/12/18 $
+00005  * $Change: 1155299 $
+00006  *
+00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009  * otherwise expressly agreed to in writing between Synopsys and you.
+00010  *
+00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012  * any End User Software License Agreement or Agreement for Licensed Product
+00013  * with Synopsys or any supplement thereto. You are permitted to use and
+00014  * redistribute this Software in source and binary forms, with or without
+00015  * modification, provided that redistributions of source code must retain this
+00016  * notice. You may not view, use, disclose, copy or distribute this file or
+00017  * any information contained herein except pursuant to this license grant from
+00018  * Synopsys. If you do not agree with this notice, including the disclaimer
+00019  * below, then you are not authorized to use the Software.
+00020  *
+00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031  * DAMAGE.
+00032  * ========================================================================== */
+00033 #if !defined(__DWC_CORE_IF_H__)
+00034 #define __DWC_CORE_IF_H__
+00035 
+00036 #include "dwc_os.h"
+00037 
+00042 struct dwc_otg_core_if;
+00043 typedef struct dwc_otg_core_if dwc_otg_core_if_t;
+00044 
+00046 #define MAX_PERIO_FIFOS 15
+00047 
+00048 #define MAX_TX_FIFOS 15
+00049 
+00051 #define MAX_EPS_CHANNELS 16
+00052 
+00053 extern dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * _reg_base_addr);
+00054 extern void dwc_otg_core_init(dwc_otg_core_if_t * _core_if);
+00055 extern void dwc_otg_cil_remove(dwc_otg_core_if_t * _core_if);
+00056 
+00057 extern void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * _core_if);
+00058 extern void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * _core_if);
+00059 
+00060 extern uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if);
+00061 extern uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if);
+00062 
+00063 extern uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if);
+00064 
+00066 extern int32_t dwc_otg_handle_common_intr(dwc_otg_core_if_t * _core_if);
+00067 
+00078 extern int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val);
+00079 extern int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if);
+00080 #define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0
+00081 #define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1
+00082 #define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2
+00083 #define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE
+00084 
+00085 extern int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val);
+00086 extern int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if);
+00087 #define dwc_param_opt_default 1
+00088 
+00096 extern int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if,
+00097                                         int32_t val);
+00098 extern int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if);
+00099 #define dwc_param_dma_enable_default 1
+00100 
+00109 extern int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if,
+00110                                              int32_t val);
+00111 extern int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if);
+00112 #define dwc_param_dma_desc_enable_default 1
+00113 
+00117 extern int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if,
+00118                                             int32_t val);
+00119 extern int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if);
+00120 #define dwc_param_dma_burst_size_default 32
+00121 
+00130 extern int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val);
+00131 extern int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if);
+00132 #define dwc_param_speed_default 0
+00133 #define DWC_SPEED_PARAM_HIGH 0
+00134 #define DWC_SPEED_PARAM_FULL 1
+00135 
+00141 extern int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t *
+00142                                                           core_if, int32_t val);
+00143 extern int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t
+00144                                                               * core_if);
+00145 #define dwc_param_host_support_fs_ls_low_power_default 0
+00146 
+00155 extern int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
+00156                                                        core_if, int32_t val);
+00157 extern int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t *
+00158                                                            core_if);
+00159 #define dwc_param_host_ls_low_power_phy_clk_default 0
+00160 #define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0
+00161 #define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1
+00162 
+00167 extern int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if,
+00168                                                  int32_t val);
+00169 extern int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t *
+00170                                                      core_if);
+00171 #define dwc_param_enable_dynamic_fifo_default 1
+00172 
+00179 extern int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if,
+00180                                             int32_t val);
+00181 extern int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if);
+00182 #define dwc_param_data_fifo_size_default 8192
+00183 
+00188 extern int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if,
+00189                                               int32_t val);
+00190 extern int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if);
+00191 #define dwc_param_dev_rx_fifo_size_default 1064
+00192 
+00197 extern int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
+00198                                                      core_if, int32_t val);
+00199 extern int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t *
+00200                                                          core_if);
+00201 #define dwc_param_dev_nperio_tx_fifo_size_default 1024
+00202 
+00207 extern int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if,
+00208                                                     int32_t val, int fifo_num);
+00209 extern int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t *
+00210                                                         core_if, int fifo_num);
+00211 #define dwc_param_dev_perio_tx_fifo_size_default 256
+00212 
+00217 extern int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if,
+00218                                                int32_t val);
+00219 extern int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if);
+00220 #define dwc_param_host_rx_fifo_size_default 1024
+00221 
+00226 extern int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
+00227                                                       core_if, int32_t val);
+00228 extern int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t *
+00229                                                           core_if);
+00230 #define dwc_param_host_nperio_tx_fifo_size_default 1024
+00231 
+00236 extern int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
+00237                                                      core_if, int32_t val);
+00238 extern int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t *
+00239                                                          core_if);
+00240 #define dwc_param_host_perio_tx_fifo_size_default 1024
+00241 
+00245 extern int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if,
+00246                                                int32_t val);
+00247 extern int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if);
+00248 #define dwc_param_max_transfer_size_default 65535
+00249 
+00253 extern int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if,
+00254                                               int32_t val);
+00255 extern int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if);
+00256 #define dwc_param_max_packet_count_default 511
+00257 
+00262 extern int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if,
+00263                                            int32_t val);
+00264 extern int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if);
+00265 #define dwc_param_host_channels_default 12
+00266 
+00273 extern int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if,
+00274                                            int32_t val);
+00275 extern int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if);
+00276 #define dwc_param_dev_endpoints_default 6
+00277 
+00286 extern int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val);
+00287 extern int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if);
+00288 #define DWC_PHY_TYPE_PARAM_FS 0
+00289 #define DWC_PHY_TYPE_PARAM_UTMI 1
+00290 #define DWC_PHY_TYPE_PARAM_ULPI 2
+00291 #define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI
+00292 
+00304 extern int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if,
+00305                                             int32_t val);
+00306 extern int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if);
+00307 #define dwc_param_phy_utmi_width_default 16
+00308 
+00319 extern int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if,
+00320                                           int32_t val);
+00321 extern int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if);
+00322 #define dwc_param_phy_ulpi_ddr_default 0
+00323 
+00328 extern int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if,
+00329                                                int32_t val);
+00330 extern int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if);
+00331 #define DWC_PHY_ULPI_INTERNAL_VBUS 0
+00332 #define DWC_PHY_ULPI_EXTERNAL_VBUS 1
+00333 #define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS
+00334 
+00341 extern int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if,
+00342                                         int32_t val);
+00343 extern int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if);
+00344 #define dwc_param_i2c_enable_default 0
+00345 
+00346 extern int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if,
+00347                                         int32_t val);
+00348 extern int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if);
+00349 #define dwc_param_ulpi_fs_ls_default 0
+00350 
+00351 extern int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val);
+00352 extern int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if);
+00353 #define dwc_param_ts_dline_default 0
+00354 
+00361 extern int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if,
+00362                                                  int32_t val);
+00363 extern int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t *
+00364                                                      core_if);
+00365 #define dwc_param_en_multiple_tx_fifo_default 1
+00366 
+00371 extern int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
+00372                                               int fifo_num, int32_t val);
+00373 extern int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if,
+00374                                                   int fifo_num);
+00375 #define dwc_param_dev_tx_fifo_size_default 256
+00376 
+00382 extern int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val);
+00383 extern int32_t dwc_otg_get_thr_ctl(dwc_otg_core_if_t * core_if, int fifo_num);
+00384 #define dwc_param_thr_ctl_default 0
+00385 
+00389 extern int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if,
+00390                                            int32_t val);
+00391 extern int32_t dwc_otg_get_tx_thr_length(dwc_otg_core_if_t * core_if);
+00392 #define dwc_param_tx_thr_length_default 64
+00393 
+00397 extern int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if,
+00398                                            int32_t val);
+00399 extern int32_t dwc_otg_get_rx_thr_length(dwc_otg_core_if_t * core_if);
+00400 #define dwc_param_rx_thr_length_default 64
+00401 
+00405 extern int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if,
+00406                                         int32_t val);
+00407 extern int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if);
+00408 #define dwc_param_lpm_enable_default 1
+00409 
+00413 extern int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if,
+00414                                         int32_t val);
+00415 extern int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if);
+00416 #define dwc_param_pti_enable_default 0
+00417 
+00421 extern int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if,
+00422                                         int32_t val);
+00423 extern int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if);
+00424 #define dwc_param_mpi_enable_default 0
+00425 
+00429 extern int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if,
+00430                                         int32_t val);
+00431 extern int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if);
+00432 #define dwc_param_ic_usb_cap_default 0
+00433 
+00434 extern int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if, int32_t val);
+00435 extern int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if);
+00436 #define dwc_param_ahb_thr_ratio_default 0
+00437 
+00445 extern void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * _core_if);
+00446 extern void dwc_otg_dump_spram(dwc_otg_core_if_t * _core_if);
+00447 extern void dwc_otg_dump_host_registers(dwc_otg_core_if_t * _core_if);
+00448 extern void dwc_otg_dump_global_registers(dwc_otg_core_if_t * _core_if);
+00449 
+00453 extern uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if);
+00454 
+00458 extern uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if);
+00459 
+00463 extern void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val);
+00464 
+00468 extern uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if);
+00469 
+00474 extern uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if);
+00475 
+00479 extern uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if);
+00483 extern void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
+00484 
+00488 extern uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if);
+00492 extern void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val);
+00493 
+00497 extern uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if);
+00501 extern void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val);
+00502 
+00506 extern uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if);
+00507 
+00511 extern uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if);
+00512 
+00516 extern uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if);
+00520 extern void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val);
+00521 
+00525 extern uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if);
+00529 extern void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val);
+00530 
+00535 extern void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val);
+00536 
+00540 extern uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if);
+00541 
+00545 extern uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if);
+00546 
+00550 extern uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if);
+00551 
+00555 extern uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if);
+00559 extern void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val);
+00560 
+00564 extern uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if);
+00568 extern void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val);
+00569 
+00573 extern uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if);
+00577 extern void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val);
+00578 
+00579 /*
+00580  * Some functions for accessing registers
+00581  */
+00582 
+00586 extern uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if);
+00587 extern void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val);
+00588 
+00592 extern uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if);
+00593 extern void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val);
+00594 
+00598 extern uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if);
+00599 extern void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
+00600 
+00604 extern uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if);
+00605 extern void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val);
+00606 
+00607 extern uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if);
+00608 extern void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val);
+00609 
+00613 extern uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if);
+00614 extern void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val);
+00615 
+00619 extern uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if);
+00620 extern void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val);
+00621 
+00625 extern uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if);
+00626 extern void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val);
+00627 
+00631 extern uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if);
+00632 
+00635 #endif                          /* __DWC_CORE_IF_H__ */
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__core__if_8h.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__core__if_8h.html new file mode 100644 index 000000000000..2aef00fc08be --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__core__if_8h.html @@ -0,0 +1,1730 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_core_if.h File Reference + + + + + + +

dwc_otg_core_if.h File Reference

This file defines DWC_OTG Core API. More... +

+#include "dwc_os.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

OTG Core Parameters

+#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE   0
+#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE   1
+#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE   2
+#define dwc_param_otg_cap_default   DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE
+#define dwc_param_opt_default   1
+#define dwc_param_dma_enable_default   1
+#define dwc_param_dma_desc_enable_default   1
+#define dwc_param_dma_burst_size_default   32
+#define dwc_param_speed_default   0
+#define DWC_SPEED_PARAM_HIGH   0
+#define DWC_SPEED_PARAM_FULL   1
+#define dwc_param_host_support_fs_ls_low_power_default   0
+#define dwc_param_host_ls_low_power_phy_clk_default   0
+#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ   0
+#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ   1
+#define dwc_param_enable_dynamic_fifo_default   1
+#define dwc_param_data_fifo_size_default   8192
+#define dwc_param_dev_rx_fifo_size_default   1064
+#define dwc_param_dev_nperio_tx_fifo_size_default   1024
+#define dwc_param_dev_perio_tx_fifo_size_default   256
+#define dwc_param_host_rx_fifo_size_default   1024
+#define dwc_param_host_nperio_tx_fifo_size_default   1024
+#define dwc_param_host_perio_tx_fifo_size_default   1024
+#define dwc_param_max_transfer_size_default   65535
+#define dwc_param_max_packet_count_default   511
+#define dwc_param_host_channels_default   12
+#define dwc_param_dev_endpoints_default   6
+#define DWC_PHY_TYPE_PARAM_FS   0
+#define DWC_PHY_TYPE_PARAM_UTMI   1
+#define DWC_PHY_TYPE_PARAM_ULPI   2
+#define dwc_param_phy_type_default   DWC_PHY_TYPE_PARAM_UTMI
+#define dwc_param_phy_utmi_width_default   16
+#define dwc_param_phy_ulpi_ddr_default   0
+#define DWC_PHY_ULPI_INTERNAL_VBUS   0
+#define DWC_PHY_ULPI_EXTERNAL_VBUS   1
+#define dwc_param_phy_ulpi_ext_vbus_default   DWC_PHY_ULPI_INTERNAL_VBUS
+#define dwc_param_i2c_enable_default   0
+#define dwc_param_ulpi_fs_ls_default   0
+#define dwc_param_ts_dline_default   0
+#define dwc_param_en_multiple_tx_fifo_default   1
+#define dwc_param_dev_tx_fifo_size_default   256
+#define dwc_param_thr_ctl_default   0
+#define dwc_param_tx_thr_length_default   64
+#define dwc_param_rx_thr_length_default   64
+#define dwc_param_lpm_enable_default   1
+#define dwc_param_pti_enable_default   0
+#define dwc_param_mpi_enable_default   0
+#define dwc_param_ic_usb_cap_default   0
+#define dwc_param_ahb_thr_ratio_default   0
int dwc_otg_set_param_otg_cap (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies the OTG capabilities.
+int32_t dwc_otg_get_param_otg_cap (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_opt (dwc_otg_core_if_t *core_if, int32_t val)
+int32_t dwc_otg_get_param_opt (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_dma_enable (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies whether to use slave or DMA mode for accessing the data FIFOs.
+int32_t dwc_otg_get_param_dma_enable (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_dma_desc_enable (dwc_otg_core_if_t *core_if, int32_t val)
 When DMA mode is enabled specifies whether to use address DMA or DMA Descritor mode for accessing the data FIFOs in device mode.
+int32_t dwc_otg_get_param_dma_desc_enable (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_dma_burst_size (dwc_otg_core_if_t *core_if, int32_t val)
 The DMA Burst size (applicable only for External DMA Mode).
+int32_t dwc_otg_get_param_dma_burst_size (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_speed (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies the maximum speed of operation in host and device mode.
+int32_t dwc_otg_get_param_speed (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_host_support_fs_ls_low_power (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies whether low power mode is supported when attached to a Full Speed or Low Speed device in host mode.
+int32_t dwc_otg_get_param_host_support_fs_ls_low_power (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_host_ls_low_power_phy_clk (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies the PHY clock rate in low power mode when connected to a Low Speed device in host mode.
+int32_t dwc_otg_get_param_host_ls_low_power_phy_clk (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_enable_dynamic_fifo (dwc_otg_core_if_t *core_if, int32_t val)
 0 - Use cC FIFO size parameters 1 - Allow dynamic FIFO sizing (default)
+int32_t dwc_otg_get_param_enable_dynamic_fifo (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_data_fifo_size (dwc_otg_core_if_t *core_if, int32_t val)
 Total number of 4-byte words in the data FIFO memory.
+int32_t dwc_otg_get_param_data_fifo_size (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_dev_rx_fifo_size (dwc_otg_core_if_t *core_if, int32_t val)
 Number of 4-byte words in the Rx FIFO in device mode when dynamic FIFO sizing is enabled.
+int32_t dwc_otg_get_param_dev_rx_fifo_size (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_dev_nperio_tx_fifo_size (dwc_otg_core_if_t *core_if, int32_t val)
 Number of 4-byte words in the non-periodic Tx FIFO in device mode when dynamic FIFO sizing is enabled.
+int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_dev_perio_tx_fifo_size (dwc_otg_core_if_t *core_if, int32_t val, int fifo_num)
 Number of 4-byte words in each of the periodic Tx FIFOs in device mode when dynamic FIFO sizing is enabled.
+int32_t dwc_otg_get_param_dev_perio_tx_fifo_size (dwc_otg_core_if_t *core_if, int fifo_num)
int dwc_otg_set_param_host_rx_fifo_size (dwc_otg_core_if_t *core_if, int32_t val)
 Number of 4-byte words in the Rx FIFO in host mode when dynamic FIFO sizing is enabled.
+int32_t dwc_otg_get_param_host_rx_fifo_size (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_host_nperio_tx_fifo_size (dwc_otg_core_if_t *core_if, int32_t val)
 Number of 4-byte words in the non-periodic Tx FIFO in host mode when Dynamic FIFO sizing is enabled in the core.
+int32_t dwc_otg_get_param_host_nperio_tx_fifo_size (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_host_perio_tx_fifo_size (dwc_otg_core_if_t *core_if, int32_t val)
 Number of 4-byte words in the host periodic Tx FIFO when dynamic FIFO sizing is enabled.
+int32_t dwc_otg_get_param_host_perio_tx_fifo_size (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_max_transfer_size (dwc_otg_core_if_t *core_if, int32_t val)
 The maximum transfer size supported in bytes.
+int32_t dwc_otg_get_param_max_transfer_size (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_max_packet_count (dwc_otg_core_if_t *core_if, int32_t val)
 The maximum number of packets in a transfer.
+int32_t dwc_otg_get_param_max_packet_count (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_host_channels (dwc_otg_core_if_t *core_if, int32_t val)
 The number of host channel registers to use.
+int32_t dwc_otg_get_param_host_channels (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_dev_endpoints (dwc_otg_core_if_t *core_if, int32_t val)
 The number of endpoints in addition to EP0 available for device mode operations.
+int32_t dwc_otg_get_param_dev_endpoints (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_phy_type (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies the type of PHY interface to use.
+int32_t dwc_otg_get_param_phy_type (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_phy_utmi_width (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies the UTMI+ Data Width.
+int32_t dwc_otg_get_param_phy_utmi_width (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_phy_ulpi_ddr (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies whether the ULPI operates at double or single data rate.
+int32_t dwc_otg_get_param_phy_ulpi_ddr (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_phy_ulpi_ext_vbus (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies whether to use the internal or external supply to drive the vbus with a ULPI phy.
+int32_t dwc_otg_get_param_phy_ulpi_ext_vbus (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_i2c_enable (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies whether to use the I2Cinterface for full speed PHY.
+int32_t dwc_otg_get_param_i2c_enable (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_ulpi_fs_ls (dwc_otg_core_if_t *core_if, int32_t val)
+int32_t dwc_otg_get_param_ulpi_fs_ls (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_ts_dline (dwc_otg_core_if_t *core_if, int32_t val)
+int32_t dwc_otg_get_param_ts_dline (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_en_multiple_tx_fifo (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies whether dedicated transmit FIFOs are enabled for non periodic IN endpoints in device mode 0 - No 1 - Yes.
+int32_t dwc_otg_get_param_en_multiple_tx_fifo (dwc_otg_core_if_t *core_if)
int dwc_otg_set_param_dev_tx_fifo_size (dwc_otg_core_if_t *core_if, int fifo_num, int32_t val)
 Number of 4-byte words in each of the Tx FIFOs in device mode when dynamic FIFO sizing is enabled.
+int32_t dwc_otg_get_param_dev_tx_fifo_size (dwc_otg_core_if_t *core_if, int fifo_num)
+int dwc_otg_set_param_thr_ctl (dwc_otg_core_if_t *core_if, int32_t val)
 Thresholding enable flag- bit 0 - enable non-ISO Tx thresholding bit 1 - enable ISO Tx thresholding bit 2 - enable Rx thresholding.
+int32_t dwc_otg_get_thr_ctl (dwc_otg_core_if_t *core_if, int fifo_num)
+int dwc_otg_set_param_tx_thr_length (dwc_otg_core_if_t *core_if, int32_t val)
 Thresholding length for Tx FIFOs in 32 bit DWORDs.
+int32_t dwc_otg_get_tx_thr_length (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_rx_thr_length (dwc_otg_core_if_t *core_if, int32_t val)
 Thresholding length for Rx FIFOs in 32 bit DWORDs.
+int32_t dwc_otg_get_rx_thr_length (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_lpm_enable (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies whether LPM (Link Power Management) support is enabled.
+int32_t dwc_otg_get_param_lpm_enable (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_pti_enable (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies whether PTI enhancement is enabled.
+int32_t dwc_otg_get_param_pti_enable (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_mpi_enable (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies whether MPI enhancement is enabled.
+int32_t dwc_otg_get_param_mpi_enable (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_ic_usb_cap (dwc_otg_core_if_t *core_if, int32_t val)
 Specifies whether IC_USB capability is enabled.
+int32_t dwc_otg_get_param_ic_usb_cap (dwc_otg_core_if_t *core_if)
+int dwc_otg_set_param_ahb_thr_ratio (dwc_otg_core_if_t *core_if, int32_t val)
+int32_t dwc_otg_get_param_ahb_thr_ratio (dwc_otg_core_if_t *core_if)

Access to registers and bit-fields

void dwc_otg_dump_dev_registers (dwc_otg_core_if_t *_core_if)
 Dump core registers and SPRAM.
void dwc_otg_dump_spram (dwc_otg_core_if_t *_core_if)
 This functions reads the SPRAM and prints its content.
void dwc_otg_dump_host_registers (dwc_otg_core_if_t *_core_if)
 This function reads the host registers and prints them.
void dwc_otg_dump_global_registers (dwc_otg_core_if_t *_core_if)
 This function reads the core global registers and prints them.
+uint32_t dwc_otg_get_hnpstatus (dwc_otg_core_if_t *core_if)
 Get host negotiation status.
+uint32_t dwc_otg_get_srpstatus (dwc_otg_core_if_t *core_if)
 Get srp status.
+void dwc_otg_set_hnpreq (dwc_otg_core_if_t *core_if, uint32_t val)
 Set hnpreq bit in the GOTGCTL register.
+uint32_t dwc_otg_get_gsnpsid (dwc_otg_core_if_t *core_if)
 Get Content of SNPSID register.
uint32_t dwc_otg_get_mode (dwc_otg_core_if_t *core_if)
 Get current mode.
+uint32_t dwc_otg_get_hnpcapable (dwc_otg_core_if_t *core_if)
 Get value of hnpcapable field in the GUSBCFG register.
+void dwc_otg_set_hnpcapable (dwc_otg_core_if_t *core_if, uint32_t val)
 Set value of hnpcapable field in the GUSBCFG register.
+uint32_t dwc_otg_get_srpcapable (dwc_otg_core_if_t *core_if)
 Get value of srpcapable field in the GUSBCFG register.
+void dwc_otg_set_srpcapable (dwc_otg_core_if_t *core_if, uint32_t val)
 Set value of srpcapable field in the GUSBCFG register.
+uint32_t dwc_otg_get_devspeed (dwc_otg_core_if_t *core_if)
 Get value of devspeed field in the DCFG register.
+void dwc_otg_set_devspeed (dwc_otg_core_if_t *core_if, uint32_t val)
 Set value of devspeed field in the DCFG register.
+uint32_t dwc_otg_get_busconnected (dwc_otg_core_if_t *core_if)
 Get the value of busconnected field from the HPRT0 register.
+uint32_t dwc_otg_get_enumspeed (dwc_otg_core_if_t *core_if)
 Gets the device enumeration Speed.
+uint32_t dwc_otg_get_prtpower (dwc_otg_core_if_t *core_if)
 Get value of prtpwr field from the HPRT0 register.
+void dwc_otg_set_prtpower (dwc_otg_core_if_t *core_if, uint32_t val)
 Set value of prtpwr field from the HPRT0 register.
+uint32_t dwc_otg_get_prtsuspend (dwc_otg_core_if_t *core_if)
 Get value of prtsusp field from the HPRT0 regsiter.
+void dwc_otg_set_prtsuspend (dwc_otg_core_if_t *core_if, uint32_t val)
 Set value of prtpwr field from the HPRT0 register.
+void dwc_otg_set_prtresume (dwc_otg_core_if_t *core_if, uint32_t val)
 Set value of prtres field from the HPRT0 register FIXME Remove?
+uint32_t dwc_otg_get_remotewakesig (dwc_otg_core_if_t *core_if)
 Get value of rmtwkupsig bit in DCTL register.
+uint32_t dwc_otg_get_lpm_portsleepstatus (dwc_otg_core_if_t *core_if)
 Get value of prt_sleep_sts field from the GLPMCFG register.
+uint32_t dwc_otg_get_lpm_remotewakeenabled (dwc_otg_core_if_t *core_if)
 Get value of rem_wkup_en field from the GLPMCFG register.
+uint32_t dwc_otg_get_lpmresponse (dwc_otg_core_if_t *core_if)
 Get value of appl_resp field from the GLPMCFG register.
+void dwc_otg_set_lpmresponse (dwc_otg_core_if_t *core_if, uint32_t val)
 Set value of appl_resp field from the GLPMCFG register.
+uint32_t dwc_otg_get_hsic_connect (dwc_otg_core_if_t *core_if)
 Get value of hsic_connect field from the GLPMCFG register.
+void dwc_otg_set_hsic_connect (dwc_otg_core_if_t *core_if, uint32_t val)
 Set value of hsic_connect field from the GLPMCFG register.
+uint32_t dwc_otg_get_inv_sel_hsic (dwc_otg_core_if_t *core_if)
 Get value of inv_sel_hsic field from the GLPMCFG register.
+void dwc_otg_set_inv_sel_hsic (dwc_otg_core_if_t *core_if, uint32_t val)
 Set value of inv_sel_hsic field from the GLPMFG register.
+uint32_t dwc_otg_get_gotgctl (dwc_otg_core_if_t *core_if)
 GOTGCTL register.
+void dwc_otg_set_gotgctl (dwc_otg_core_if_t *core_if, uint32_t val)
+uint32_t dwc_otg_get_gusbcfg (dwc_otg_core_if_t *core_if)
 GUSBCFG register.
+void dwc_otg_set_gusbcfg (dwc_otg_core_if_t *core_if, uint32_t val)
+uint32_t dwc_otg_get_grxfsiz (dwc_otg_core_if_t *core_if)
 GRXFSIZ register.
+void dwc_otg_set_grxfsiz (dwc_otg_core_if_t *core_if, uint32_t val)
+uint32_t dwc_otg_get_gnptxfsiz (dwc_otg_core_if_t *core_if)
 GNPTXFSIZ register.
+void dwc_otg_set_gnptxfsiz (dwc_otg_core_if_t *core_if, uint32_t val)
+uint32_t dwc_otg_get_gpvndctl (dwc_otg_core_if_t *core_if)
+void dwc_otg_set_gpvndctl (dwc_otg_core_if_t *core_if, uint32_t val)
+uint32_t dwc_otg_get_ggpio (dwc_otg_core_if_t *core_if)
 GGPIO register.
+void dwc_otg_set_ggpio (dwc_otg_core_if_t *core_if, uint32_t val)
+uint32_t dwc_otg_get_guid (dwc_otg_core_if_t *core_if)
 GUID register.
+void dwc_otg_set_guid (dwc_otg_core_if_t *core_if, uint32_t val)
+uint32_t dwc_otg_get_hprt0 (dwc_otg_core_if_t *core_if)
 HPRT0 register.
+void dwc_otg_set_hprt0 (dwc_otg_core_if_t *core_if, uint32_t val)
+uint32_t dwc_otg_get_hptxfsiz (dwc_otg_core_if_t *core_if)
 GHPTXFSIZE.

Defines

+#define __DWC_CORE_IF_H__
+#define MAX_PERIO_FIFOS   15
 Maximum number of Periodic FIFOs.
+#define MAX_TX_FIFOS   15
 Maximum number of Periodic FIFOs.
+#define MAX_EPS_CHANNELS   16
 Maximum number of Endpoints/HostChannels.

Typedefs

+typedef dwc_otg_core_if dwc_otg_core_if_t

Functions

dwc_otg_core_if_tdwc_otg_cil_init (const uint32_t *_reg_base_addr)
 This function is called to initialize the DWC_otg CSR data structures.
void dwc_otg_core_init (dwc_otg_core_if_t *_core_if)
 This function initializes the DWC_otg controller registers and prepares the core for device mode or host mode operation.
void dwc_otg_cil_remove (dwc_otg_core_if_t *_core_if)
 This function frees the structures allocated by dwc_otg_cil_init().
void dwc_otg_enable_global_interrupts (dwc_otg_core_if_t *_core_if)
 This function enables the controller's Global Interrupt in the AHB Config register.
void dwc_otg_disable_global_interrupts (dwc_otg_core_if_t *_core_if)
 This function disables the controller's Global Interrupt in the AHB Config register.
+uint8_t dwc_otg_is_device_mode (dwc_otg_core_if_t *_core_if)
+uint8_t dwc_otg_is_host_mode (dwc_otg_core_if_t *_core_if)
+uint8_t dwc_otg_is_dma_enable (dwc_otg_core_if_t *core_if)
int32_t dwc_otg_handle_common_intr (dwc_otg_core_if_t *_core_if)
 This function should be called on every hardware interrupt.
+


Detailed Description

+This file defines DWC_OTG Core API. +

+ +

+Definition in file dwc_otg_core_if.h.


Function Documentation

+ +
+
+ + + + + + + + + +
dwc_otg_core_if_t* dwc_otg_cil_init (const uint32_t *  reg_base_addr  ) 
+
+
+ +

+This function is called to initialize the DWC_otg CSR data structures. +

+The register addresses in the device and host structures are initialized from the base address supplied by the caller. The calling function must make the OS calls to get the base address of the DWC_otg controller registers. The core_params argument holds the parameters that specify how the core should be configured.

+

Parameters:
+ + +
reg_base_addr Base address of DWC_otg core registers
+
+ +

+Definition at line 78 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_core_init (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function initializes the DWC_otg controller registers and prepares the core for device mode or host mode operation. +

+

Parameters:
+ + +
core_if Programming view of the DWC_otg controller
+
+ +

+Definition at line 467 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_cil_remove (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function frees the structures allocated by dwc_otg_cil_init(). +

+

Parameters:
+ + +
core_if The core interface pointer returned from dwc_otg_cil_init().
+
+ +

+Definition at line 265 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_enable_global_interrupts (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function enables the controller's Global Interrupt in the AHB Config register. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 292 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_disable_global_interrupts (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function disables the controller's Global Interrupt in the AHB Config register. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 305 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_handle_common_intr (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function should be called on every hardware interrupt. +

+The common interrupts are those that occur in both Host and Device mode. This handler handles the following interrupts:

    +
  • Mode Mismatch Interrupt
  • Disconnect Interrupt
  • OTG Interrupt
  • Connector ID Status Change Interrupt
  • Session Request Interrupt.
  • Resume / Remote Wakeup Detected Interrupt.
  • LPM Transaction Received Interrutp
+ +

+Definition at line 800 of file dwc_otg_cil_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_otg_cap (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Specifies the OTG capabilities. +

+The driver will automatically detect the value for this parameter if none is specified. 0 - HNP and SRP capable (default) 1 - SRP Only capable 2 - No HNP/SRP capable +

+Definition at line 4056 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_dma_enable (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Specifies whether to use slave or DMA mode for accessing the data FIFOs. +

+The driver will automatically detect the value for this parameter if none is specified. 0 - Slave 1 - DMA (default, if available) +

+Definition at line 4135 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_dma_desc_enable (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+When DMA mode is enabled specifies whether to use address DMA or DMA Descritor mode for accessing the data FIFOs in device mode. +

+The driver will automatically detect the value for this parameter if none is specified. 0 - address DMA 1 - DMA Descriptor(default, if available) +

+Definition at line 4165 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_dma_burst_size (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+The DMA Burst size (applicable only for External DMA Mode). +

+1, 4, 8 16, 32, 64, 128, 256 (default 32) +

+Definition at line 4959 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_speed (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Specifies the maximum speed of operation in host and device mode. +

+The actual speed depends on the speed of the attached device and the value of phy_type. The actual speed depends on the speed of the attached device. 0 - High Speed (default) 1 - Full Speed +

+Definition at line 4601 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_host_support_fs_ls_low_power (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Specifies whether low power mode is supported when attached to a Full Speed or Low Speed device in host mode. +

+0 - Don't support low power mode (default) 1 - Support low power mode +

+Definition at line 4195 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_host_ls_low_power_phy_clk (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Specifies the PHY clock rate in low power mode when connected to a Low Speed device in host mode. +

+This parameter is applicable only if HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS then defaults to 6 MHZ otherwise 48 MHZ.

+0 - 48 MHz 1 - 6 MHz +

+Definition at line 4630 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_data_fifo_size (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Total number of 4-byte words in the data FIFO memory. +

+This memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic Tx FIFOs. 32 to 32768 (default 8192) Note: The total FIFO memory depth in the FPGA configuration is 8192. +

+Definition at line 4242 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_dev_rx_fifo_size (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Number of 4-byte words in the Rx FIFO in device mode when dynamic FIFO sizing is enabled. +

+16 to 32768 (default 1064) +

+Definition at line 4271 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_dev_nperio_tx_fifo_size (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Number of 4-byte words in the non-periodic Tx FIFO in device mode when dynamic FIFO sizing is enabled. +

+16 to 32768 (default 1024) +

+Definition at line 4297 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_dev_perio_tx_fifo_size (dwc_otg_core_if_t core_if,
int32_t  val,
int  fifo_num 
)
+
+
+ +

+Number of 4-byte words in each of the periodic Tx FIFOs in device mode when dynamic FIFO sizing is enabled. +

+4 to 768 (default 256) +

+Definition at line 4779 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_host_rx_fifo_size (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Number of 4-byte words in the Rx FIFO in host mode when dynamic FIFO sizing is enabled. +

+16 to 32768 (default 1024) +

+Definition at line 4330 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_host_nperio_tx_fifo_size (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Number of 4-byte words in the non-periodic Tx FIFO in host mode when Dynamic FIFO sizing is enabled in the core. +

+16 to 32768 (default 1024) +

+Definition at line 4362 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_host_perio_tx_fifo_size (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Number of 4-byte words in the host periodic Tx FIFO when dynamic FIFO sizing is enabled. +

+16 to 32768 (default 1024) +

+Definition at line 4395 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_max_transfer_size (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+The maximum transfer size supported in bytes. +

+2047 to 65,535 (default 65,535) +

+Definition at line 4428 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_max_packet_count (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+The maximum number of packets in a transfer. +

+15 to 511 (default 511) +

+Definition at line 4461 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_host_channels (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+The number of host channel registers to use. +

+1 to 16 (default 12) Note: The FPGA configuration supports a maximum of 12 host channels. +

+Definition at line 4492 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_dev_endpoints (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+The number of endpoints in addition to EP0 available for device mode operations. +

+1 to 15 (default 6 IN and OUT) Note: The FPGA configuration supports a maximum of 6 IN and OUT endpoints in addition to EP0. +

+Definition at line 4522 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_phy_type (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Specifies the type of PHY interface to use. +

+By default, the driver will automatically detect the phy_type.

+0 - Full Speed PHY 1 - UTMI+ (default) 2 - ULPI +

+Definition at line 4552 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_phy_utmi_width (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Specifies the UTMI+ Data Width. +

+This parameter is applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI PHY_TYPE, this parameter indicates the data width between the MAC and the ULPI Wrapper.) Also, this parameter is applicable only if the OTG_HSPHY_WIDTH cC parameter was set to "8 and 16 bits", meaning that the core has been configured to work at either data path width.

+8 or 16 bits (default 16) +

+Definition at line 4700 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_phy_ulpi_ddr (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Specifies whether the ULPI operates at double or single data rate. +

+This parameter is only applicable if PHY_TYPE is ULPI.

+0 - single data rate ULPI interface with 8 bit wide data bus (default) 1 - double data rate ULPI interface with 4 bit wide data bus +

+Definition at line 4665 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_i2c_enable (dwc_otg_core_if_t core_if,
int32_t  val 
)
+
+
+ +

+Specifies whether to use the I2Cinterface for full speed PHY. +

+This parameter is only applicable if PHY_TYPE is FS. 0 - No (default) 1 - Yes +

+Definition at line 4751 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_set_param_dev_tx_fifo_size (dwc_otg_core_if_t core_if,
int  fifo_num,
int32_t  val 
)
+
+
+ +

+Number of 4-byte words in each of the Tx FIFOs in device mode when dynamic FIFO sizing is enabled. +

+4 to 768 (default 256) +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_dump_dev_registers (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+Dump core registers and SPRAM. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 3347 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_dump_spram (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This functions reads the SPRAM and prints its content. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 3477 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_dump_host_registers (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function reads the host registers and prints them. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 3505 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_dump_global_registers (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This function reads the core global registers and prints them. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 3573 of file dwc_otg_cil.c. +

+

+ +

+
+ + + + + + + + + +
uint32_t dwc_otg_get_mode (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+Get current mode. +

+Returns 0 if in device mode, and 1 if in host mode. +

+Definition at line 5115 of file dwc_otg_cil.c. +

+

+


Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__dbg_8h-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__dbg_8h-source.html new file mode 100644 index 000000000000..824e31765117 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__dbg_8h-source.html @@ -0,0 +1,100 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_dbg.h Source File + + + + + + +

dwc_otg_dbg.h

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  *
+00003  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00004  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00005  * otherwise expressly agreed to in writing between Synopsys and you.
+00006  * 
+00007  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00008  * any End User Software License Agreement or Agreement for Licensed Product
+00009  * with Synopsys or any supplement thereto. You are permitted to use and
+00010  * redistribute this Software in source and binary forms, with or without
+00011  * modification, provided that redistributions of source code must retain this
+00012  * notice. You may not view, use, disclose, copy or distribute this file or
+00013  * any information contained herein except pursuant to this license grant from
+00014  * Synopsys. If you do not agree with this notice, including the disclaimer
+00015  * below, then you are not authorized to use the Software.
+00016  * 
+00017  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00020  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00021  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00022  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00023  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00024  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00027  * DAMAGE.
+00028  * ========================================================================== */
+00029 
+00030 #ifndef __DWC_OTG_DBG_H__
+00031 #define __DWC_OTG_DBG_H__
+00032 
+00041 extern uint32_t g_dbg_lvl;
+00045 static inline uint32_t SET_DEBUG_LEVEL(const uint32_t new)
+00046 {
+00047         uint32_t old = g_dbg_lvl;
+00048         g_dbg_lvl = new;
+00049         return old;
+00050 }
+00051 
+00053 #define DBG_CIL         (0x2)
+00054 
+00056 #define DBG_CILV        (0x20)
+00057 
+00059 #define DBG_PCD         (0x4)
+00060 
+00062 #define DBG_PCDV        (0x40)
+00063 
+00064 #define DBG_HCD         (0x8)
+00065 
+00067 #define DBG_HCDV        (0x80)
+00068 
+00070 #define DBG_HCD_URB     (0x800)
+00071 
+00073 #define DBG_ANY         (0xFF)
+00074 
+00076 #define DBG_OFF         0
+00077 
+00079 #define USB_DWC "DWC_otg: "
+00080 
+00098 #ifdef DEBUG
+00099 
+00100 # define DWC_DEBUGPL(lvl, x...) do{ if ((lvl)&g_dbg_lvl)__DWC_DEBUG(USB_DWC x ); }while(0)
+00101 # define DWC_DEBUGP(x...)       DWC_DEBUGPL(DBG_ANY, x )
+00102 
+00103 # define CHK_DEBUG_LEVEL(level) ((level) & g_dbg_lvl)
+00104 
+00105 #else
+00106 
+00107 # define DWC_DEBUGPL(lvl, x...) do{}while(0)
+00108 # define DWC_DEBUGP(x...)
+00109 
+00110 # define CHK_DEBUG_LEVEL(level) (0)
+00111 
+00112 #endif /*DEBUG*/
+00113 #endif
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__dbg_8h.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__dbg_8h.html new file mode 100644 index 000000000000..7fef85df6f7b --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__dbg_8h.html @@ -0,0 +1,133 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_dbg.h File Reference + + + + + + +

dwc_otg_dbg.h File Reference

This file defines debug levels. More... +

+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Defines

+#define DBG_CIL   (0x2)
 When debug level has the DBG_CIL bit set, display CIL Debug messages.
+#define DBG_CILV   (0x20)
 When debug level has the DBG_CILV bit set, display CIL Verbose debug messages.
+#define DBG_PCD   (0x4)
 When debug level has the DBG_PCD bit set, display PCD (Device) debug messages.
+#define DBG_PCDV   (0x40)
 When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug messages.
+#define DBG_HCD   (0x8)
 When debug level has the DBG_HCD bit set, display Host debug messages.
+#define DBG_HCDV   (0x80)
 When debug level has the DBG_HCDV bit set, display Verbose Host debug messages.
+#define DBG_HCD_URB   (0x800)
 When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host mode.
+#define DBG_ANY   (0xFF)
 When debug level has any bit set, display debug messages.
+#define DBG_OFF   0
 All debug messages off.
+#define USB_DWC   "DWC_otg: "
 Prefix string for DWC_DEBUG print macros.
#define DWC_DEBUGPL(lvl, x...)   do{}while(0)
 Print a debug message when the Global debug level variable contains the bit defined in lvl.
+#define DWC_DEBUGP(x...)
+#define CHK_DEBUG_LEVEL(level)   (0)

Functions

+static uint32_t SET_DEBUG_LEVEL (const uint32_t new)
 Set the Debug Level variable.

Variables

+uint32_t g_dbg_lvl
 The Debug Level bit-mask variable.
+


Detailed Description

+This file defines debug levels. +

+Debugging support vanishes in non-debug builds. +

+Definition in file dwc_otg_dbg.h.


Define Documentation

+ +
+
+ + + + + + + + + + + + +
#define DWC_DEBUGPL (lvl,
x...   )    do{}while(0)
+
+
+ +

+Print a debug message when the Global debug level variable contains the bit defined in lvl. +

+

Parameters:
+ + + +
[in] lvl - Debug level, use one of the DBG_ constants above.
[in] x - like printf
+
+Example:

+ DWC_DEBUGPL( DBG_ANY, "%s(%p)\n", __func__, _reg_base_addr);
+ results in:
+ usb-DWC_otg: dwc_otg_cil_init(ca867000) +

+Definition at line 107 of file dwc_otg_dbg.h. +

+

+


Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__driver_8c-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__driver_8c-source.html new file mode 100644 index 000000000000..850bcb593382 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__driver_8c-source.html @@ -0,0 +1,1079 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_driver.c Source File + + + + + + +

dwc_otg_driver.c

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.c $
+00003  * $Revision: #76 $
+00004  * $Date: 2009/05/03 $
+00005  * $Change: 1245589 $
+00006  *
+00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009  * otherwise expressly agreed to in writing between Synopsys and you.
+00010  *
+00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012  * any End User Software License Agreement or Agreement for Licensed Product
+00013  * with Synopsys or any supplement thereto. You are permitted to use and
+00014  * redistribute this Software in source and binary forms, with or without
+00015  * modification, provided that redistributions of source code must retain this
+00016  * notice. You may not view, use, disclose, copy or distribute this file or
+00017  * any information contained herein except pursuant to this license grant from
+00018  * Synopsys. If you do not agree with this notice, including the disclaimer
+00019  * below, then you are not authorized to use the Software.
+00020  *
+00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031  * DAMAGE.
+00032  * ========================================================================== */
+00033 
+00051 #include <linux/kernel.h>
+00052 #include <linux/module.h>
+00053 #include <linux/moduleparam.h>
+00054 #include <linux/init.h>
+00055 #include <linux/device.h>
+00056 #include <linux/errno.h>
+00057 #include <linux/types.h>
+00058 #include <linux/stat.h>         /* permission constants */
+00059 #include <linux/version.h>
+00060 #include <linux/interrupt.h>
+00061 
+00062 #ifdef LM_INTERFACE
+00063 #include <asm/arch/regs-irq.h>
+00064 #include <asm/arch/lm.h>
+00065 #include <asm/sizes.h>
+00066 #endif
+00067 
+00068 # include <linux/irq.h>
+00069 
+00070 #include <asm/io.h>
+00071 
+00072 
+00073 #include "dwc_os.h"
+00074 #include "dwc_otg_dbg.h"
+00075 #include "dwc_otg_driver.h"
+00076 #include "dwc_otg_attr.h"
+00077 #include "dwc_otg_core_if.h"
+00078 #include "dwc_otg_pcd_if.h"
+00079 #include "dwc_otg_hcd_if.h"
+00080 
+00081 #define DWC_DRIVER_VERSION      "2.90a 23-APR-2009"
+00082 #define DWC_DRIVER_DESC         "HS OTG USB Controller driver"
+00083 
+00084 static const char dwc_driver_name[] = "dwc_otg";
+00085 
+00086 extern int pcd_init(
+00087 #ifdef LM_INTERFACE
+00088         struct lm_device *_dev
+00089 #elif  PCI_INTERFACE
+00090         struct pci_dev *_dev
+00091 #endif
+00092         );
+00093 extern int hcd_init(
+00094 #ifdef LM_INTERFACE
+00095         struct lm_device *_dev
+00096 #elif  PCI_INTERFACE
+00097         struct pci_dev *_dev
+00098 #endif
+00099         );
+00100 
+00101 extern int pcd_remove(
+00102 #ifdef LM_INTERFACE
+00103         struct lm_device *_dev
+00104 #elif  PCI_INTERFACE
+00105         struct pci_dev *_dev
+00106 #endif
+00107         );
+00108 
+00109 extern void hcd_remove(
+00110 #ifdef LM_INTERFACE
+00111         struct lm_device *_dev
+00112 #elif  PCI_INTERFACE
+00113         struct pci_dev *_dev
+00114 #endif
+00115         );
+00116 
+00117 /*-------------------------------------------------------------------------*/
+00118 /* Encapsulate the module parameter settings */
+00119 
+00120 struct dwc_otg_driver_module_params {
+00121         int32_t opt;
+00122         int32_t otg_cap;
+00123         int32_t dma_enable;
+00124         int32_t dma_desc_enable;
+00125         int32_t dma_burst_size;
+00126         int32_t speed;
+00127         int32_t host_support_fs_ls_low_power;
+00128         int32_t host_ls_low_power_phy_clk;
+00129         int32_t enable_dynamic_fifo;
+00130         int32_t data_fifo_size;
+00131         int32_t dev_rx_fifo_size;
+00132         int32_t dev_nperio_tx_fifo_size;
+00133         uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
+00134         int32_t host_rx_fifo_size;
+00135         int32_t host_nperio_tx_fifo_size;
+00136         int32_t host_perio_tx_fifo_size;
+00137         int32_t max_transfer_size;
+00138         int32_t max_packet_count;
+00139         int32_t host_channels;
+00140         int32_t dev_endpoints;
+00141         int32_t phy_type;
+00142         int32_t phy_utmi_width;
+00143         int32_t phy_ulpi_ddr;
+00144         int32_t phy_ulpi_ext_vbus;
+00145         int32_t i2c_enable;
+00146         int32_t ulpi_fs_ls;
+00147         int32_t ts_dline;
+00148         int32_t en_multiple_tx_fifo;
+00149         uint32_t dev_tx_fifo_size[MAX_TX_FIFOS];
+00150         uint32_t thr_ctl;
+00151         uint32_t tx_thr_length;
+00152         uint32_t rx_thr_length;
+00153         int32_t pti_enable;
+00154         int32_t mpi_enable;
+00155         int32_t lpm_enable;
+00156         int32_t ic_usb_cap;
+00157         int32_t ahb_thr_ratio;
+00158 };
+00159 
+00160 static struct dwc_otg_driver_module_params dwc_otg_module_params = {
+00161         .opt = -1,
+00162         .otg_cap = -1,
+00163         .dma_enable = -1,
+00164         .dma_desc_enable = -1,
+00165         .dma_burst_size = -1,
+00166         .speed = -1,
+00167         .host_support_fs_ls_low_power = -1,
+00168         .host_ls_low_power_phy_clk = -1,
+00169         .enable_dynamic_fifo = -1,
+00170         .data_fifo_size = -1,
+00171         .dev_rx_fifo_size = -1,
+00172         .dev_nperio_tx_fifo_size = -1,
+00173         .dev_perio_tx_fifo_size = {
+00174                                    /* dev_perio_tx_fifo_size_1 */
+00175                                    -1,
+00176                                    -1,
+00177                                    -1,
+00178                                    -1,
+00179                                    -1,
+00180                                    -1,
+00181                                    -1,
+00182                                    -1,
+00183                                    -1,
+00184                                    -1,
+00185                                    -1,
+00186                                    -1,
+00187                                    -1,
+00188                                    -1,
+00189                                    -1
+00190                                    /* 15 */
+00191                                    },
+00192         .host_rx_fifo_size = -1,
+00193         .host_nperio_tx_fifo_size = -1,
+00194         .host_perio_tx_fifo_size = -1,
+00195         .max_transfer_size = -1,
+00196         .max_packet_count = -1,
+00197         .host_channels = -1,
+00198         .dev_endpoints = -1,
+00199         .phy_type = -1,
+00200         .phy_utmi_width = -1,
+00201         .phy_ulpi_ddr = -1,
+00202         .phy_ulpi_ext_vbus = -1,
+00203         .i2c_enable = -1,
+00204         .ulpi_fs_ls = -1,
+00205         .ts_dline = -1,
+00206         .en_multiple_tx_fifo = -1,
+00207         .dev_tx_fifo_size = {
+00208                              /* dev_tx_fifo_size */
+00209                              -1,
+00210                              -1,
+00211                              -1,
+00212                              -1,
+00213                              -1,
+00214                              -1,
+00215                              -1,
+00216                              -1,
+00217                              -1,
+00218                              -1,
+00219                              -1,
+00220                              -1,
+00221                              -1,
+00222                              -1,
+00223                              -1
+00224                              /* 15 */
+00225                              },
+00226         .thr_ctl = -1,
+00227         .tx_thr_length = -1,
+00228         .rx_thr_length = -1,
+00229         .pti_enable = -1,
+00230         .mpi_enable = -1,
+00231         .lpm_enable = -1,
+00232         .ic_usb_cap = -1,
+00233         .ahb_thr_ratio = -1,
+00234 };
+00235 
+00239 static ssize_t version_show(struct device_driver *dev, char *buf)
+00240 {
+00241         return snprintf(buf, sizeof(DWC_DRIVER_VERSION) + 2, "%s\n",
+00242                         DWC_DRIVER_VERSION);
+00243 }
+00244 
+00245 static DRIVER_ATTR(version, S_IRUGO, version_show, NULL);
+00246 
+00250 uint32_t g_dbg_lvl = 0;         /* OFF */
+00251 
+00255 static ssize_t dbg_level_show(struct device_driver *drv, char *buf)
+00256 {
+00257         return sprintf(buf, "0x%0x\n", g_dbg_lvl);
+00258 }
+00259 
+00263 static ssize_t dbg_level_store(struct device_driver *drv, const char *buf,
+00264                                size_t count)
+00265 {
+00266         g_dbg_lvl = simple_strtoul(buf, NULL, 16);
+00267         return count;
+00268 }
+00269 
+00270 static DRIVER_ATTR(debuglevel, S_IRUGO | S_IWUSR, dbg_level_show,
+00271                    dbg_level_store);
+00272 
+00277 static int set_parameters(dwc_otg_core_if_t * core_if)
+00278 {
+00279         int retval = 0;
+00280         int i;
+00281 
+00282         if (dwc_otg_module_params.otg_cap != -1) {
+00283                 retval +=
+00284                     dwc_otg_set_param_otg_cap(core_if,
+00285                                               dwc_otg_module_params.otg_cap);
+00286         }
+00287         if (dwc_otg_module_params.dma_enable != -1) {
+00288                 retval +=
+00289                     dwc_otg_set_param_dma_enable(core_if,
+00290                                                  dwc_otg_module_params.
+00291                                                  dma_enable);
+00292         }
+00293         if (dwc_otg_module_params.dma_desc_enable != -1) {
+00294                 retval +=
+00295                     dwc_otg_set_param_dma_desc_enable(core_if,
+00296                                                       dwc_otg_module_params.
+00297                                                       dma_desc_enable);
+00298         }
+00299         if (dwc_otg_module_params.opt != -1) {
+00300                 retval +=
+00301                     dwc_otg_set_param_opt(core_if, dwc_otg_module_params.opt);
+00302         }
+00303         if (dwc_otg_module_params.dma_burst_size != -1) {
+00304                 retval +=
+00305                     dwc_otg_set_param_dma_burst_size(core_if,
+00306                                                      dwc_otg_module_params.
+00307                                                      dma_burst_size);
+00308         }
+00309         if (dwc_otg_module_params.host_support_fs_ls_low_power != -1) {
+00310                 retval +=
+00311                     dwc_otg_set_param_host_support_fs_ls_low_power(core_if,
+00312                                                                    dwc_otg_module_params.
+00313                                                                    host_support_fs_ls_low_power);
+00314         }
+00315         if (dwc_otg_module_params.enable_dynamic_fifo != -1) {
+00316                 retval +=
+00317                     dwc_otg_set_param_enable_dynamic_fifo(core_if,
+00318                                                           dwc_otg_module_params.
+00319                                                           enable_dynamic_fifo);
+00320         }
+00321         if (dwc_otg_module_params.data_fifo_size != -1) {
+00322                 retval +=
+00323                     dwc_otg_set_param_data_fifo_size(core_if,
+00324                                                      dwc_otg_module_params.
+00325                                                      data_fifo_size);
+00326         }
+00327         if (dwc_otg_module_params.dev_rx_fifo_size != -1) {
+00328                 retval +=
+00329                     dwc_otg_set_param_dev_rx_fifo_size(core_if,
+00330                                                        dwc_otg_module_params.
+00331                                                        dev_rx_fifo_size);
+00332         }
+00333         if (dwc_otg_module_params.dev_nperio_tx_fifo_size != -1) {
+00334                 retval +=
+00335                     dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if,
+00336                                                               dwc_otg_module_params.
+00337                                                               dev_nperio_tx_fifo_size);
+00338         }
+00339         if (dwc_otg_module_params.host_rx_fifo_size != -1) {
+00340                 retval +=
+00341                     dwc_otg_set_param_host_rx_fifo_size(core_if,
+00342                                                         dwc_otg_module_params.host_rx_fifo_size);
+00343         }
+00344         if (dwc_otg_module_params.host_nperio_tx_fifo_size != -1) {
+00345                 retval +=
+00346                     dwc_otg_set_param_host_nperio_tx_fifo_size(core_if,
+00347                                                                dwc_otg_module_params.
+00348                                                                host_nperio_tx_fifo_size);
+00349         }
+00350         if (dwc_otg_module_params.host_perio_tx_fifo_size != -1) {
+00351                 retval +=
+00352                     dwc_otg_set_param_host_perio_tx_fifo_size(core_if,
+00353                                                               dwc_otg_module_params.
+00354                                                               host_perio_tx_fifo_size);
+00355         }
+00356         if (dwc_otg_module_params.max_transfer_size != -1) {
+00357                 retval +=
+00358                     dwc_otg_set_param_max_transfer_size(core_if,
+00359                                                         dwc_otg_module_params.
+00360                                                         max_transfer_size);
+00361         }
+00362         if (dwc_otg_module_params.max_packet_count != -1) {
+00363                 retval +=
+00364                     dwc_otg_set_param_max_packet_count(core_if,
+00365                                                        dwc_otg_module_params.
+00366                                                        max_packet_count);
+00367         }
+00368         if (dwc_otg_module_params.host_channels != -1) {
+00369                 retval +=
+00370                     dwc_otg_set_param_host_channels(core_if,
+00371                                                     dwc_otg_module_params.
+00372                                                     host_channels);
+00373         }
+00374         if (dwc_otg_module_params.dev_endpoints != -1) {
+00375                 retval +=
+00376                     dwc_otg_set_param_dev_endpoints(core_if,
+00377                                                     dwc_otg_module_params.
+00378                                                     dev_endpoints);
+00379         }
+00380         if (dwc_otg_module_params.phy_type != -1) {
+00381                 retval +=
+00382                     dwc_otg_set_param_phy_type(core_if,
+00383                                                dwc_otg_module_params.phy_type);
+00384         }
+00385         if (dwc_otg_module_params.speed != -1) {
+00386                 retval +=
+00387                     dwc_otg_set_param_speed(core_if,
+00388                                             dwc_otg_module_params.speed);
+00389         }
+00390         if (dwc_otg_module_params.host_ls_low_power_phy_clk != -1) {
+00391                 retval +=
+00392                     dwc_otg_set_param_host_ls_low_power_phy_clk(core_if,
+00393                                                                 dwc_otg_module_params.
+00394                                                                 host_ls_low_power_phy_clk);
+00395         }
+00396         if (dwc_otg_module_params.phy_ulpi_ddr != -1) {
+00397                 retval +=
+00398                     dwc_otg_set_param_phy_ulpi_ddr(core_if,
+00399                                                    dwc_otg_module_params.
+00400                                                    phy_ulpi_ddr);
+00401         }
+00402         if (dwc_otg_module_params.phy_ulpi_ext_vbus != -1) {
+00403                 retval +=
+00404                     dwc_otg_set_param_phy_ulpi_ext_vbus(core_if,
+00405                                                         dwc_otg_module_params.
+00406                                                         phy_ulpi_ext_vbus);
+00407         }
+00408         if (dwc_otg_module_params.phy_utmi_width != -1) {
+00409                 retval +=
+00410                     dwc_otg_set_param_phy_utmi_width(core_if,
+00411                                                      dwc_otg_module_params.
+00412                                                      phy_utmi_width);
+00413         }
+00414         if (dwc_otg_module_params.ulpi_fs_ls != -1) {
+00415                 retval +=
+00416                     dwc_otg_set_param_ulpi_fs_ls(core_if, dwc_otg_module_params.ulpi_fs_ls);
+00417         }
+00418         if (dwc_otg_module_params.ts_dline != -1) {
+00419                 retval +=
+00420                     dwc_otg_set_param_ts_dline(core_if,
+00421                                                dwc_otg_module_params.ts_dline);
+00422         }
+00423         if (dwc_otg_module_params.i2c_enable != -1) {
+00424                 retval +=
+00425                     dwc_otg_set_param_i2c_enable(core_if,
+00426                                                  dwc_otg_module_params.
+00427                                                  i2c_enable);
+00428         }
+00429         if (dwc_otg_module_params.en_multiple_tx_fifo != -1) {
+00430                 retval +=
+00431                     dwc_otg_set_param_en_multiple_tx_fifo(core_if,
+00432                                                           dwc_otg_module_params.
+00433                                                           en_multiple_tx_fifo);
+00434         }
+00435         for (i = 0; i < 15; i++) {
+00436                 if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] != -1) {
+00437                         retval +=
+00438                             dwc_otg_set_param_dev_perio_tx_fifo_size(core_if,
+00439                                                                      dwc_otg_module_params.
+00440                                                                      dev_perio_tx_fifo_size
+00441                                                                      [i], i);
+00442                 }
+00443         }
+00444 
+00445         for (i = 0; i < 15; i++) {
+00446                 if (dwc_otg_module_params.dev_tx_fifo_size[i] != -1) {
+00447                         retval += dwc_otg_set_param_dev_tx_fifo_size(core_if,
+00448                                                                      dwc_otg_module_params.
+00449                                                                      dev_tx_fifo_size
+00450                                                                      [i], i);
+00451                 }
+00452         }
+00453         if (dwc_otg_module_params.thr_ctl != -1) {
+00454                 retval +=
+00455                     dwc_otg_set_param_thr_ctl(core_if,
+00456                                               dwc_otg_module_params.thr_ctl);
+00457         }
+00458         if (dwc_otg_module_params.mpi_enable != -1) {
+00459                 retval +=
+00460                     dwc_otg_set_param_mpi_enable(core_if,
+00461                                                  dwc_otg_module_params.
+00462                                                  mpi_enable);
+00463         }
+00464         if (dwc_otg_module_params.pti_enable != -1) {
+00465                 retval +=
+00466                     dwc_otg_set_param_pti_enable(core_if,
+00467                                                  dwc_otg_module_params.
+00468                                                  pti_enable);
+00469         }
+00470         if (dwc_otg_module_params.lpm_enable != -1) {
+00471                 retval +=
+00472                     dwc_otg_set_param_lpm_enable(core_if,
+00473                                                  dwc_otg_module_params.
+00474                                                  lpm_enable);
+00475         }
+00476         if (dwc_otg_module_params.ic_usb_cap != -1) {
+00477                 retval +=
+00478                     dwc_otg_set_param_ic_usb_cap(core_if,
+00479                                                  dwc_otg_module_params.
+00480                                                  ic_usb_cap);
+00481         }
+00482         if (dwc_otg_module_params.tx_thr_length != -1) {
+00483                 retval +=
+00484                     dwc_otg_set_param_tx_thr_length(core_if,
+00485                                                     dwc_otg_module_params.tx_thr_length);
+00486         }
+00487         if (dwc_otg_module_params.rx_thr_length != -1) {
+00488                 retval +=
+00489                     dwc_otg_set_param_rx_thr_length(core_if,
+00490                                                     dwc_otg_module_params.
+00491                                                     rx_thr_length);
+00492         }
+00493         if(dwc_otg_module_params.ahb_thr_ratio != -1) {
+00494                 retval +=
+00495                     dwc_otg_set_param_ahb_thr_ratio(core_if, dwc_otg_module_params.ahb_thr_ratio);
+00496         }
+00497         return retval;
+00498 }
+00499 
+00504 static irqreturn_t dwc_otg_common_irq(int irq, void *dev)
+00505 {
+00506         dwc_otg_device_t *otg_dev = dev;
+00507         int32_t retval = IRQ_NONE;
+00508 
+00509         retval = dwc_otg_handle_common_intr(otg_dev->core_if);
+00510         if (retval != 0) {
+00511                 S3C2410X_CLEAR_EINTPEND();
+00512         }
+00513         return IRQ_RETVAL(retval);
+00514 }
+00515 
+00525 static void dwc_otg_driver_remove(
+00526 #ifdef LM_INTERFACE
+00527      struct lm_device *_dev
+00528 #elif PCI_INTERFACE
+00529      struct pci_dev *_dev
+00530 #endif
+00531 )
+00532 
+00533 {
+00534 #ifdef LM_INTERFACE
+00535         dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
+00536 #elif PCI_INTERFACE
+00537         dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
+00538 #endif
+00539 
+00540 
+00541         DWC_DEBUGPL(DBG_ANY, "%s(%p)\n", __func__, _dev);
+00542 
+00543         if (!otg_dev) {
+00544                 /* Memory allocation for the dwc_otg_device failed. */
+00545                 DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
+00546                 return;
+00547         }
+00548 #ifndef DWC_DEVICE_ONLY
+00549         if (otg_dev->hcd) {
+00550                 hcd_remove(_dev);
+00551         } else {
+00552                 DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
+00553                 return;
+00554         }
+00555 #endif
+00556 
+00557 #ifndef DWC_HOST_ONLY
+00558         if (otg_dev->pcd) {
+00559                 pcd_remove(_dev);
+00560         }
+00561 #endif
+00562         /*
+00563          * Free the IRQ
+00564          */
+00565         if (otg_dev->common_irq_installed) {
+00566                 free_irq(_dev->irq, otg_dev);
+00567         }
+00568 
+00569         if (otg_dev->core_if) {
+00570                 dwc_otg_cil_remove(otg_dev->core_if);
+00571         }
+00572 
+00573         /*
+00574          * Remove the device attributes
+00575          */
+00576         dwc_otg_attr_remove(_dev);
+00577 
+00578         /*
+00579          * Return the memory.
+00580          */
+00581         if (otg_dev->base) {
+00582                 iounmap(otg_dev->base);
+00583         }
+00584         dwc_free(otg_dev);
+00585 
+00586         /*
+00587          * Clear the drvdata pointer.
+00588          */
+00589 #ifdef LM_INTERFACE
+00590         lm_set_drvdata(_dev, 0);
+00591 #elif PCI_INTERFACE
+00592         release_mem_region(otg_dev->rsrc_start, otg_dev->rsrc_len);
+00593         pci_set_drvdata(_dev, 0);
+00594 #endif
+00595 }
+00596 
+00608 static int dwc_otg_driver_probe(
+00609 #ifdef LM_INTERFACE
+00610 struct lm_device *_dev
+00611 #elif PCI_INTERFACE
+00612 struct pci_dev *_dev,  const struct pci_device_id *id
+00613 #endif
+00614 )
+00615 {
+00616         int retval = 0;
+00617         dwc_otg_device_t *dwc_otg_device;
+00618 
+00619         dev_dbg(&_dev->dev, "dwc_otg_driver_probe(%p)\n", _dev);
+00620 #ifdef LM_INTERFACE
+00621         dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)_dev->resource.start);
+00622 #elif PCI_INTERFACE
+00623         if (!id) {
+00624         DWC_ERROR("Invalid pci_device_id %p", id);
+00625                 return -EINVAL;
+00626         }
+00627 
+00628         if (!_dev || (pci_enable_device(_dev) < 0)) {
+00629                 DWC_ERROR("Invalid pci_device %p", _dev);
+00630                 return -ENODEV;
+00631         }
+00632         dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)pci_resource_start(_dev,0));
+00633         /* other stuff needed as well? */
+00634 
+00635 #endif
+00636 
+00637 
+00638         dwc_otg_device = dwc_alloc(sizeof(dwc_otg_device_t));
+00639 
+00640         if (!dwc_otg_device) {
+00641                 dev_err(&_dev->dev, "kmalloc of dwc_otg_device failed\n");
+00642                 retval = -ENOMEM;
+00643                 goto fail;
+00644         }
+00645 
+00646         memset(dwc_otg_device, 0, sizeof(*dwc_otg_device));
+00647         dwc_otg_device->reg_offset = 0xFFFFFFFF;
+00648 
+00649         /*
+00650          * Map the DWC_otg Core memory into virtual address space.
+00651          */
+00652 #ifdef LM_INTERFACE
+00653         dwc_otg_device->base = ioremap(_dev->resource.start, SZ_256K);
+00654 
+00655         if (!dwc_otg_device->base) {
+00656                 dev_err(&_dev->dev, "ioremap() failed\n");
+00657                 retval = -ENOMEM;
+00658                 goto fail;
+00659         }
+00660         dev_dbg(&_dev->dev, "base=0x%08x\n", (unsigned)dwc_otg_device->base);
+00661 #elif PCI_INTERFACE
+00662         _dev->current_state = PCI_D0;
+00663         _dev->dev.power.power_state = PMSG_ON;
+00664         
+00665         if (!_dev->irq) {
+00666                 DWC_ERROR("Found HC with no IRQ. Check BIOS/PCI %s setup!", pci_name(_dev));
+00667                 retval = -ENODEV;
+00668                 goto fail;
+00669         }
+00670 
+00671         dwc_otg_device->rsrc_start = pci_resource_start(_dev,0);
+00672         dwc_otg_device->rsrc_len = pci_resource_len(_dev,0);
+00673         DWC_DEBUGPL(DBG_ANY,"PCI resource: start=%08x, len=%08x\n",
+00674                     dwc_otg_device->rsrc_start,
+00675                     dwc_otg_device->rsrc_len);
+00676         if (!request_mem_region(dwc_otg_device->rsrc_start, dwc_otg_device->rsrc_len, "dwc_otg")) {
+00677           dev_dbg(&_dev->dev, "error mapping memory\n");
+00678           retval = -EFAULT;
+00679           goto fail;
+00680         }
+00681 
+00682         dwc_otg_device->base = ioremap_nocache(dwc_otg_device->rsrc_start, dwc_otg_device->rsrc_len);
+00683         if (dwc_otg_device->base == NULL) {
+00684                 dev_dbg(&_dev->dev, "error mapping memory\n");
+00685                 retval = -EFAULT;
+00686                 goto fail;
+00687         }
+00688         dev_dbg(&_dev->dev, "base=0x%p (before adjust) \n", dwc_otg_device->base);
+00689         dwc_otg_device->base = (char *)dwc_otg_device->base;
+00690         dev_dbg(&_dev->dev, "base=0x%p (after adjust) \n", dwc_otg_device->base);
+00691         dev_dbg(&_dev->dev, "%s: mapped PA 0x%x to VA 0x%p\n", __func__,
+00692                 (unsigned)dwc_otg_device->rsrc_start, dwc_otg_device->base);
+00693         //
+00694         pci_set_drvdata(_dev, dwc_otg_device); 
+00695         pci_set_master(_dev);
+00696 #endif
+00697 
+00698         /*
+00699          * Initialize driver data to point to the global DWC_otg
+00700          * Device structure.
+00701          */
+00702 #ifdef LM_INTERFACE
+00703         lm_set_drvdata(_dev, dwc_otg_device);
+00704 #endif
+00705         dev_dbg(&_dev->dev, "dwc_otg_device=0x%p\n", dwc_otg_device);
+00706 
+00707         dwc_otg_device->core_if = dwc_otg_cil_init(dwc_otg_device->base);
+00708         if (!dwc_otg_device->core_if) {
+00709                 dev_err(&_dev->dev, "CIL initialization failed!\n");
+00710                 retval = -ENOMEM;
+00711                 goto fail;
+00712         }
+00713 
+00714         /*
+00715          * Attempt to ensure this device is really a DWC_otg Controller.
+00716          * Read and verify the SNPSID register contents. The value should be
+00717          * 0x45F42XXX, which corresponds to "OT2", as in "OTG version 2.XX".
+00718          */
+00719 
+00720         if ((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) !=
+00721             0x4F542000) {
+00722                 dev_err(&_dev->dev, "Bad value for SNPSID: 0x%08x\n",
+00723                         dwc_otg_get_gsnpsid(dwc_otg_device->core_if));
+00724                 dwc_otg_cil_remove(dwc_otg_device->core_if);
+00725                 dwc_free(dwc_otg_device);
+00726                 retval = -EINVAL;
+00727                 goto fail;
+00728         }
+00729 
+00730         /*
+00731          * Validate parameter values.
+00732          */
+00733         if (set_parameters(dwc_otg_device->core_if)) {
+00734                 dwc_otg_cil_remove(dwc_otg_device->core_if);
+00735                 retval = -EINVAL;
+00736                 goto fail;
+00737         }
+00738 
+00739         /*
+00740          * Create Device Attributes in sysfs
+00741          */
+00742         dwc_otg_attr_create(_dev);
+00743 
+00744         /*
+00745          * Disable the global interrupt until all the interrupt
+00746          * handlers are installed.
+00747          */
+00748         dwc_otg_disable_global_interrupts(dwc_otg_device->core_if);
+00749 
+00750         /*
+00751          * Install the interrupt handler for the common interrupts before
+00752          * enabling common interrupts in core_init below.
+00753          */
+00754         DWC_DEBUGPL(DBG_CIL, "registering (common) handler for irq%d\n",
+00755                     _dev->irq);
+00756         retval = request_irq(_dev->irq, dwc_otg_common_irq,
+00757                              SA_SHIRQ, "dwc_otg", dwc_otg_device);
+00758         if (retval) {
+00759                 DWC_ERROR("request of irq%d failed\n", _dev->irq);
+00760                 retval = -EBUSY;
+00761                 goto fail;
+00762         } else {
+00763                 dwc_otg_device->common_irq_installed = 1;
+00764         }
+00765 
+00766 #ifdef LM_INTERFACE
+00767         set_irq_type(_dev->irq, IRQT_LOW);
+00768 #endif
+00769 
+00770         /*
+00771          * Initialize the DWC_otg core.
+00772          */
+00773         dwc_otg_core_init(dwc_otg_device->core_if);
+00774 
+00775 #ifndef DWC_HOST_ONLY
+00776         /*
+00777          * Initialize the PCD
+00778          */
+00779         retval = pcd_init(_dev);
+00780         if (retval != 0) {
+00781                 DWC_ERROR("pcd_init failed\n");
+00782                 dwc_otg_device->pcd = NULL;
+00783                 goto fail;
+00784         }
+00785 #endif
+00786 #ifndef DWC_DEVICE_ONLY
+00787         /*
+00788          * Initialize the HCD
+00789          */
+00790         retval = hcd_init(_dev);
+00791         if (retval != 0) {
+00792                 DWC_ERROR("hcd_init failed\n");
+00793                 dwc_otg_device->hcd = NULL;
+00794                 goto fail;
+00795         }
+00796 #endif
+00797 #ifdef PCI_INTERFACE    
+00798         pci_set_drvdata(_dev, dwc_otg_device);
+00799 #endif
+00800 
+00801         /*
+00802          * Enable the global interrupt after all the interrupt
+00803          * handlers are installed.
+00804          */
+00805         dwc_otg_enable_global_interrupts(dwc_otg_device->core_if);
+00806 
+00807         return 0;
+00808 
+00809       fail:
+00810         dwc_otg_driver_remove(_dev);
+00811         return retval;
+00812 }
+00813 
+00825 #ifdef LM_INTERFACE
+00826 static struct lm_driver dwc_otg_driver = {
+00827         .drv = {
+00828                 .name = (char *)dwc_driver_name,
+00829                 },
+00830         .probe = dwc_otg_driver_probe,
+00831         .remove = dwc_otg_driver_remove,
+00832 };
+00833 #elif PCI_INTERFACE
+00834 static const struct pci_device_id pci_ids[] = { {
+00835         PCI_DEVICE(0x16c3, 0xabcd),
+00836         .driver_data = (unsigned long) 0xdeadbeef,
+00837         }, { /* end: all zeroes */ }
+00838 };
+00839 MODULE_DEVICE_TABLE(pci, pci_ids);
+00840 
+00841 /* pci driver glue; this is a "new style" PCI driver module */
+00842 static struct pci_driver dwc_otg_driver = {
+00843         .name =         "dwc_otg",
+00844         .id_table =     pci_ids,
+00845 
+00846         .probe =        dwc_otg_driver_probe,
+00847         .remove =       dwc_otg_driver_remove,
+00848 
+00849         .driver = {
+00850                 .name   = (char*)dwc_driver_name,
+00851         },
+00852 };
+00853 #endif
+00854 
+00855 
+00866 static int __init dwc_otg_driver_init(void)
+00867 {
+00868         int retval = 0;
+00869         int error;
+00870         printk(KERN_INFO "%s: version %s\n", dwc_driver_name,
+00871                DWC_DRIVER_VERSION);
+00872 #ifdef LM_INTERFACE
+00873         retval = lm_driver_register(&dwc_otg_driver);
+00874 #elif PCI_INTERFACE
+00875         retval = pci_register_driver(&dwc_otg_driver);
+00876 #endif
+00877         if (retval < 0) {
+00878                 printk(KERN_ERR "%s retval=%d\n", __func__, retval);
+00879                 return retval;
+00880         }
+00881 #ifdef LM_INTERFACE
+00882         error = driver_create_file(&dwc_otg_driver.drv, &driver_attr_version);
+00883         error = driver_create_file(&dwc_otg_driver.drv, &driver_attr_debuglevel);
+00884 #elif PCI_INTERFACE
+00885         error = driver_create_file(&dwc_otg_driver.driver, &driver_attr_version);
+00886         error = driver_create_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
+00887 #endif
+00888         return retval;
+00889 }
+00890 
+00891 module_init(dwc_otg_driver_init);
+00892 
+00899 static void __exit dwc_otg_driver_cleanup(void)
+00900 {
+00901         printk(KERN_DEBUG "dwc_otg_driver_cleanup()\n");
+00902 
+00903 #ifdef LM_INTERFACE
+00904         driver_remove_file(&dwc_otg_driver.drv, &driver_attr_debuglevel);
+00905         driver_remove_file(&dwc_otg_driver.drv, &driver_attr_version);
+00906         lm_driver_unregister(&dwc_otg_driver);
+00907 #elif PCI_INTERFACE
+00908         driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel);
+00909         driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version);
+00910         pci_unregister_driver(&dwc_otg_driver);
+00911 #endif
+00912 
+00913         printk(KERN_INFO "%s module removed\n", dwc_driver_name);
+00914 }
+00915 module_exit(dwc_otg_driver_cleanup);
+00916 
+00917 MODULE_DESCRIPTION(DWC_DRIVER_DESC);
+00918 MODULE_AUTHOR("Synopsys Inc.");
+00919 MODULE_LICENSE("GPL");
+00920 
+00921 module_param_named(otg_cap, dwc_otg_module_params.otg_cap, int, 0444);
+00922 MODULE_PARM_DESC(otg_cap, "OTG Capabilities 0=HNP&SRP 1=SRP Only 2=None");
+00923 module_param_named(opt, dwc_otg_module_params.opt, int, 0444);
+00924 MODULE_PARM_DESC(opt, "OPT Mode");
+00925 module_param_named(dma_enable, dwc_otg_module_params.dma_enable, int, 0444);
+00926 MODULE_PARM_DESC(dma_enable, "DMA Mode 0=Slave 1=DMA enabled");
+00927 
+00928 module_param_named(dma_desc_enable, dwc_otg_module_params.dma_desc_enable, int,
+00929                    0444);
+00930 MODULE_PARM_DESC(dma_desc_enable,
+00931                  "DMA Desc Mode 0=Address DMA 1=DMA Descriptor enabled");
+00932 
+00933 module_param_named(dma_burst_size, dwc_otg_module_params.dma_burst_size, int,
+00934                    0444);
+00935 MODULE_PARM_DESC(dma_burst_size,
+00936                  "DMA Burst Size 1, 4, 8, 16, 32, 64, 128, 256");
+00937 module_param_named(speed, dwc_otg_module_params.speed, int, 0444);
+00938 MODULE_PARM_DESC(speed, "Speed 0=High Speed 1=Full Speed");
+00939 module_param_named(host_support_fs_ls_low_power,
+00940                    dwc_otg_module_params.host_support_fs_ls_low_power, int,
+00941                    0444);
+00942 MODULE_PARM_DESC(host_support_fs_ls_low_power,
+00943                  "Support Low Power w/FS or LS 0=Support 1=Don't Support");
+00944 module_param_named(host_ls_low_power_phy_clk,
+00945                    dwc_otg_module_params.host_ls_low_power_phy_clk, int, 0444);
+00946 MODULE_PARM_DESC(host_ls_low_power_phy_clk,
+00947                  "Low Speed Low Power Clock 0=48Mhz 1=6Mhz");
+00948 module_param_named(enable_dynamic_fifo,
+00949                    dwc_otg_module_params.enable_dynamic_fifo, int, 0444);
+00950 MODULE_PARM_DESC(enable_dynamic_fifo, "0=cC Setting 1=Allow Dynamic Sizing");
+00951 module_param_named(data_fifo_size, dwc_otg_module_params.data_fifo_size, int,
+00952                    0444);
+00953 MODULE_PARM_DESC(data_fifo_size,
+00954                  "Total number of words in the data FIFO memory 32-32768");
+00955 module_param_named(dev_rx_fifo_size, dwc_otg_module_params.dev_rx_fifo_size,
+00956                    int, 0444);
+00957 MODULE_PARM_DESC(dev_rx_fifo_size, "Number of words in the Rx FIFO 16-32768");
+00958 module_param_named(dev_nperio_tx_fifo_size,
+00959                    dwc_otg_module_params.dev_nperio_tx_fifo_size, int, 0444);
+00960 MODULE_PARM_DESC(dev_nperio_tx_fifo_size,
+00961                  "Number of words in the non-periodic Tx FIFO 16-32768");
+00962 module_param_named(dev_perio_tx_fifo_size_1,
+00963                    dwc_otg_module_params.dev_perio_tx_fifo_size[0], int, 0444);
+00964 MODULE_PARM_DESC(dev_perio_tx_fifo_size_1,
+00965                  "Number of words in the periodic Tx FIFO 4-768");
+00966 module_param_named(dev_perio_tx_fifo_size_2,
+00967                    dwc_otg_module_params.dev_perio_tx_fifo_size[1], int, 0444);
+00968 MODULE_PARM_DESC(dev_perio_tx_fifo_size_2,
+00969                  "Number of words in the periodic Tx FIFO 4-768");
+00970 module_param_named(dev_perio_tx_fifo_size_3,
+00971                    dwc_otg_module_params.dev_perio_tx_fifo_size[2], int, 0444);
+00972 MODULE_PARM_DESC(dev_perio_tx_fifo_size_3,
+00973                  "Number of words in the periodic Tx FIFO 4-768");
+00974 module_param_named(dev_perio_tx_fifo_size_4,
+00975                    dwc_otg_module_params.dev_perio_tx_fifo_size[3], int, 0444);
+00976 MODULE_PARM_DESC(dev_perio_tx_fifo_size_4,
+00977                  "Number of words in the periodic Tx FIFO 4-768");
+00978 module_param_named(dev_perio_tx_fifo_size_5,
+00979                    dwc_otg_module_params.dev_perio_tx_fifo_size[4], int, 0444);
+00980 MODULE_PARM_DESC(dev_perio_tx_fifo_size_5,
+00981                  "Number of words in the periodic Tx FIFO 4-768");
+00982 module_param_named(dev_perio_tx_fifo_size_6,
+00983                    dwc_otg_module_params.dev_perio_tx_fifo_size[5], int, 0444);
+00984 MODULE_PARM_DESC(dev_perio_tx_fifo_size_6,
+00985                  "Number of words in the periodic Tx FIFO 4-768");
+00986 module_param_named(dev_perio_tx_fifo_size_7,
+00987                    dwc_otg_module_params.dev_perio_tx_fifo_size[6], int, 0444);
+00988 MODULE_PARM_DESC(dev_perio_tx_fifo_size_7,
+00989                  "Number of words in the periodic Tx FIFO 4-768");
+00990 module_param_named(dev_perio_tx_fifo_size_8,
+00991                    dwc_otg_module_params.dev_perio_tx_fifo_size[7], int, 0444);
+00992 MODULE_PARM_DESC(dev_perio_tx_fifo_size_8,
+00993                  "Number of words in the periodic Tx FIFO 4-768");
+00994 module_param_named(dev_perio_tx_fifo_size_9,
+00995                    dwc_otg_module_params.dev_perio_tx_fifo_size[8], int, 0444);
+00996 MODULE_PARM_DESC(dev_perio_tx_fifo_size_9,
+00997                  "Number of words in the periodic Tx FIFO 4-768");
+00998 module_param_named(dev_perio_tx_fifo_size_10,
+00999                    dwc_otg_module_params.dev_perio_tx_fifo_size[9], int, 0444);
+01000 MODULE_PARM_DESC(dev_perio_tx_fifo_size_10,
+01001                  "Number of words in the periodic Tx FIFO 4-768");
+01002 module_param_named(dev_perio_tx_fifo_size_11,
+01003                    dwc_otg_module_params.dev_perio_tx_fifo_size[10], int, 0444);
+01004 MODULE_PARM_DESC(dev_perio_tx_fifo_size_11,
+01005                  "Number of words in the periodic Tx FIFO 4-768");
+01006 module_param_named(dev_perio_tx_fifo_size_12,
+01007                    dwc_otg_module_params.dev_perio_tx_fifo_size[11], int, 0444);
+01008 MODULE_PARM_DESC(dev_perio_tx_fifo_size_12,
+01009                  "Number of words in the periodic Tx FIFO 4-768");
+01010 module_param_named(dev_perio_tx_fifo_size_13,
+01011                    dwc_otg_module_params.dev_perio_tx_fifo_size[12], int, 0444);
+01012 MODULE_PARM_DESC(dev_perio_tx_fifo_size_13,
+01013                  "Number of words in the periodic Tx FIFO 4-768");
+01014 module_param_named(dev_perio_tx_fifo_size_14,
+01015                    dwc_otg_module_params.dev_perio_tx_fifo_size[13], int, 0444);
+01016 MODULE_PARM_DESC(dev_perio_tx_fifo_size_14,
+01017                  "Number of words in the periodic Tx FIFO 4-768");
+01018 module_param_named(dev_perio_tx_fifo_size_15,
+01019                    dwc_otg_module_params.dev_perio_tx_fifo_size[14], int, 0444);
+01020 MODULE_PARM_DESC(dev_perio_tx_fifo_size_15,
+01021                  "Number of words in the periodic Tx FIFO 4-768");
+01022 module_param_named(host_rx_fifo_size, dwc_otg_module_params.host_rx_fifo_size,
+01023                    int, 0444);
+01024 MODULE_PARM_DESC(host_rx_fifo_size, "Number of words in the Rx FIFO 16-32768");
+01025 module_param_named(host_nperio_tx_fifo_size,
+01026                    dwc_otg_module_params.host_nperio_tx_fifo_size, int, 0444);
+01027 MODULE_PARM_DESC(host_nperio_tx_fifo_size,
+01028                  "Number of words in the non-periodic Tx FIFO 16-32768");
+01029 module_param_named(host_perio_tx_fifo_size,
+01030                    dwc_otg_module_params.host_perio_tx_fifo_size, int, 0444);
+01031 MODULE_PARM_DESC(host_perio_tx_fifo_size,
+01032                  "Number of words in the host periodic Tx FIFO 16-32768");
+01033 module_param_named(max_transfer_size, dwc_otg_module_params.max_transfer_size,
+01034                    int, 0444);
+01036 MODULE_PARM_DESC(max_transfer_size,
+01037                  "The maximum transfer size supported in bytes 2047-65535");
+01038 module_param_named(max_packet_count, dwc_otg_module_params.max_packet_count,
+01039                    int, 0444);
+01040 MODULE_PARM_DESC(max_packet_count,
+01041                  "The maximum number of packets in a transfer 15-511");
+01042 module_param_named(host_channels, dwc_otg_module_params.host_channels, int,
+01043                    0444);
+01044 MODULE_PARM_DESC(host_channels,
+01045                  "The number of host channel registers to use 1-16");
+01046 module_param_named(dev_endpoints, dwc_otg_module_params.dev_endpoints, int,
+01047                    0444);
+01048 MODULE_PARM_DESC(dev_endpoints,
+01049                  "The number of endpoints in addition to EP0 available for device mode 1-15");
+01050 module_param_named(phy_type, dwc_otg_module_params.phy_type, int, 0444);
+01051 MODULE_PARM_DESC(phy_type, "0=Reserved 1=UTMI+ 2=ULPI");
+01052 module_param_named(phy_utmi_width, dwc_otg_module_params.phy_utmi_width, int,
+01053                    0444);
+01054 MODULE_PARM_DESC(phy_utmi_width, "Specifies the UTMI+ Data Width 8 or 16 bits");
+01055 module_param_named(phy_ulpi_ddr, dwc_otg_module_params.phy_ulpi_ddr, int, 0444);
+01056 MODULE_PARM_DESC(phy_ulpi_ddr,
+01057                  "ULPI at double or single data rate 0=Single 1=Double");
+01058 module_param_named(phy_ulpi_ext_vbus, dwc_otg_module_params.phy_ulpi_ext_vbus,
+01059                    int, 0444);
+01060 MODULE_PARM_DESC(phy_ulpi_ext_vbus,
+01061                  "ULPI PHY using internal or external vbus 0=Internal");
+01062 module_param_named(i2c_enable, dwc_otg_module_params.i2c_enable, int, 0444);
+01063 MODULE_PARM_DESC(i2c_enable, "FS PHY Interface");
+01064 module_param_named(ulpi_fs_ls, dwc_otg_module_params.ulpi_fs_ls, int, 0444);
+01065 MODULE_PARM_DESC(ulpi_fs_ls, "ULPI PHY FS/LS mode only");
+01066 module_param_named(ts_dline, dwc_otg_module_params.ts_dline, int, 0444);
+01067 MODULE_PARM_DESC(ts_dline, "Term select Dline pulsing for all PHYs");
+01068 module_param_named(debug, g_dbg_lvl, int, 0444);
+01069 MODULE_PARM_DESC(debug, "");
+01070 
+01071 module_param_named(en_multiple_tx_fifo,
+01072                    dwc_otg_module_params.en_multiple_tx_fifo, int, 0444);
+01073 MODULE_PARM_DESC(en_multiple_tx_fifo,
+01074                  "Dedicated Non Periodic Tx FIFOs 0=disabled 1=enabled");
+01075 module_param_named(dev_tx_fifo_size_1,
+01076                    dwc_otg_module_params.dev_tx_fifo_size[0], int, 0444);
+01077 MODULE_PARM_DESC(dev_tx_fifo_size_1, "Number of words in the Tx FIFO 4-768");
+01078 module_param_named(dev_tx_fifo_size_2,
+01079                    dwc_otg_module_params.dev_tx_fifo_size[1], int, 0444);
+01080 MODULE_PARM_DESC(dev_tx_fifo_size_2, "Number of words in the Tx FIFO 4-768");
+01081 module_param_named(dev_tx_fifo_size_3,
+01082                    dwc_otg_module_params.dev_tx_fifo_size[2], int, 0444);
+01083 MODULE_PARM_DESC(dev_tx_fifo_size_3, "Number of words in the Tx FIFO 4-768");
+01084 module_param_named(dev_tx_fifo_size_4,
+01085                    dwc_otg_module_params.dev_tx_fifo_size[3], int, 0444);
+01086 MODULE_PARM_DESC(dev_tx_fifo_size_4, "Number of words in the Tx FIFO 4-768");
+01087 module_param_named(dev_tx_fifo_size_5,
+01088                    dwc_otg_module_params.dev_tx_fifo_size[4], int, 0444);
+01089 MODULE_PARM_DESC(dev_tx_fifo_size_5, "Number of words in the Tx FIFO 4-768");
+01090 module_param_named(dev_tx_fifo_size_6,
+01091                    dwc_otg_module_params.dev_tx_fifo_size[5], int, 0444);
+01092 MODULE_PARM_DESC(dev_tx_fifo_size_6, "Number of words in the Tx FIFO 4-768");
+01093 module_param_named(dev_tx_fifo_size_7,
+01094                    dwc_otg_module_params.dev_tx_fifo_size[6], int, 0444);
+01095 MODULE_PARM_DESC(dev_tx_fifo_size_7, "Number of words in the Tx FIFO 4-768");
+01096 module_param_named(dev_tx_fifo_size_8,
+01097                    dwc_otg_module_params.dev_tx_fifo_size[7], int, 0444);
+01098 MODULE_PARM_DESC(dev_tx_fifo_size_8, "Number of words in the Tx FIFO 4-768");
+01099 module_param_named(dev_tx_fifo_size_9,
+01100                    dwc_otg_module_params.dev_tx_fifo_size[8], int, 0444);
+01101 MODULE_PARM_DESC(dev_tx_fifo_size_9, "Number of words in the Tx FIFO 4-768");
+01102 module_param_named(dev_tx_fifo_size_10,
+01103                    dwc_otg_module_params.dev_tx_fifo_size[9], int, 0444);
+01104 MODULE_PARM_DESC(dev_tx_fifo_size_10, "Number of words in the Tx FIFO 4-768");
+01105 module_param_named(dev_tx_fifo_size_11,
+01106                    dwc_otg_module_params.dev_tx_fifo_size[10], int, 0444);
+01107 MODULE_PARM_DESC(dev_tx_fifo_size_11, "Number of words in the Tx FIFO 4-768");
+01108 module_param_named(dev_tx_fifo_size_12,
+01109                    dwc_otg_module_params.dev_tx_fifo_size[11], int, 0444);
+01110 MODULE_PARM_DESC(dev_tx_fifo_size_12, "Number of words in the Tx FIFO 4-768");
+01111 module_param_named(dev_tx_fifo_size_13,
+01112                    dwc_otg_module_params.dev_tx_fifo_size[12], int, 0444);
+01113 MODULE_PARM_DESC(dev_tx_fifo_size_13, "Number of words in the Tx FIFO 4-768");
+01114 module_param_named(dev_tx_fifo_size_14,
+01115                    dwc_otg_module_params.dev_tx_fifo_size[13], int, 0444);
+01116 MODULE_PARM_DESC(dev_tx_fifo_size_14, "Number of words in the Tx FIFO 4-768");
+01117 module_param_named(dev_tx_fifo_size_15,
+01118                    dwc_otg_module_params.dev_tx_fifo_size[14], int, 0444);
+01119 MODULE_PARM_DESC(dev_tx_fifo_size_15, "Number of words in the Tx FIFO 4-768");
+01120 
+01121 module_param_named(thr_ctl, dwc_otg_module_params.thr_ctl, int, 0444);
+01122 MODULE_PARM_DESC(thr_ctl,
+01123                  "Thresholding enable flag bit 0 - non ISO Tx thr., 1 - ISO Tx thr., 2 - Rx thr.- bit 0=disabled 1=enabled");
+01124 module_param_named(tx_thr_length, dwc_otg_module_params.tx_thr_length, int,
+01125                    0444);
+01126 MODULE_PARM_DESC(tx_thr_length, "Tx Threshold length in 32 bit DWORDs");
+01127 module_param_named(rx_thr_length, dwc_otg_module_params.rx_thr_length, int,
+01128                    0444);
+01129 MODULE_PARM_DESC(rx_thr_length, "Rx Threshold length in 32 bit DWORDs");
+01130 
+01131 module_param_named(pti_enable, dwc_otg_module_params.pti_enable, int, 0444);
+01132 module_param_named(mpi_enable, dwc_otg_module_params.mpi_enable, int, 0444);
+01133 module_param_named(lpm_enable, dwc_otg_module_params.lpm_enable, int, 0444);
+01134 MODULE_PARM_DESC(lpm_enable, "LPM Enable 0=LPM Disabled 1=LPM Enabled");
+01135 module_param_named(ic_usb_cap, dwc_otg_module_params.ic_usb_cap, int, 0444);
+01136 MODULE_PARM_DESC(ic_usb_cap,
+01137                  "IC_USB Capability 0=IC_USB Disabled 1=IC_USB Enabled");
+01138 module_param_named(ahb_thr_ratio, dwc_otg_module_params.ahb_thr_ratio, int, 0444);
+01139 MODULE_PARM_DESC(ahb_thr_ratio, "AHB Threshold Ratio");
+01140 
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__driver_8c.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__driver_8c.html new file mode 100644 index 000000000000..33071a8d22d7 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__driver_8c.html @@ -0,0 +1,719 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_driver.c File Reference + + + + + + +

dwc_otg_driver.c File Reference

The dwc_otg_driver module provides the initialization and cleanup entry points for the DWC_otg driver. More... +

+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/stat.h>
+#include <linux/version.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <asm/io.h>
+#include "dwc_os.h"
+#include "dwc_otg_dbg.h"
+#include "dwc_otg_driver.h"
+#include "dwc_otg_attr.h"
+#include "dwc_otg_core_if.h"
+#include "dwc_otg_pcd_if.h"
+#include "dwc_otg_hcd_if.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Structures

struct  dwc_otg_driver_module_params

Defines

+#define DWC_DRIVER_VERSION   "2.90a 23-APR-2009"
+#define DWC_DRIVER_DESC   "HS OTG USB Controller driver"

Functions

+int pcd_init ()
 This function initialized the PCD portion of the driver.
int hcd_init ()
 Initializes the HCD.
+int pcd_remove ()
 Cleanup the PCD.
void hcd_remove ()
 Removes the HCD.
+static ssize_t version_show (struct device_driver *dev, char *buf)
 This function shows the Driver Version.
+static DRIVER_ATTR (version, S_IRUGO, version_show, NULL)
+static ssize_t dbg_level_show (struct device_driver *drv, char *buf)
 This function shows the driver Debug Level.
+static ssize_t dbg_level_store (struct device_driver *drv, const char *buf, size_t count)
 This function stores the driver Debug Level.
+static DRIVER_ATTR (debuglevel, S_IRUGO|S_IWUSR, dbg_level_show, dbg_level_store)
+static int set_parameters (dwc_otg_core_if_t *core_if)
 This function is called during module intialization to pass module parameters to the DWC_OTG CORE.
+static irqreturn_t dwc_otg_common_irq (int irq, void *dev)
 This function is the top level interrupt handler for the Common (Device and host modes) interrupts.
static void dwc_otg_driver_remove ()
 This function is called when a lm_device is unregistered with the dwc_otg_driver.
static int dwc_otg_driver_probe ()
 This function is called when an lm_device is bound to a dwc_otg_driver.
static int __init dwc_otg_driver_init (void)
 This function is called when the dwc_otg_driver is installed with the insmod command.
module_init (dwc_otg_driver_init)
static void __exit dwc_otg_driver_cleanup (void)
 This function is called when the driver is removed from the kernel with the rmmod command.
module_exit (dwc_otg_driver_cleanup)
MODULE_DESCRIPTION (DWC_DRIVER_DESC)
MODULE_AUTHOR ("Synopsys Inc.")
MODULE_LICENSE ("GPL")
module_param_named (otg_cap, dwc_otg_module_params.otg_cap, int, 0444)
MODULE_PARM_DESC (otg_cap,"OTG Capabilities 0=HNP&SRP 1=SRP Only 2=None")
module_param_named (opt, dwc_otg_module_params.opt, int, 0444)
MODULE_PARM_DESC (opt,"OPT Mode")
module_param_named (dma_enable, dwc_otg_module_params.dma_enable, int, 0444)
MODULE_PARM_DESC (dma_enable,"DMA Mode 0=Slave 1=DMA enabled")
module_param_named (dma_desc_enable, dwc_otg_module_params.dma_desc_enable, int, 0444)
MODULE_PARM_DESC (dma_desc_enable,"DMA Desc Mode 0=Address DMA 1=DMA Descriptor enabled")
module_param_named (dma_burst_size, dwc_otg_module_params.dma_burst_size, int, 0444)
MODULE_PARM_DESC (dma_burst_size,"DMA Burst Size 1, 4, 8, 16, 32, 64, 128, 256")
module_param_named (speed, dwc_otg_module_params.speed, int, 0444)
MODULE_PARM_DESC (speed,"Speed 0=High Speed 1=Full Speed")
module_param_named (host_support_fs_ls_low_power, dwc_otg_module_params.host_support_fs_ls_low_power, int, 0444)
MODULE_PARM_DESC (host_support_fs_ls_low_power,"Support Low Power w/FS or LS 0=Support 1=Don't Support")
module_param_named (host_ls_low_power_phy_clk, dwc_otg_module_params.host_ls_low_power_phy_clk, int, 0444)
MODULE_PARM_DESC (host_ls_low_power_phy_clk,"Low Speed Low Power Clock 0=48Mhz 1=6Mhz")
module_param_named (enable_dynamic_fifo, dwc_otg_module_params.enable_dynamic_fifo, int, 0444)
MODULE_PARM_DESC (enable_dynamic_fifo,"0=cC Setting 1=Allow Dynamic Sizing")
module_param_named (data_fifo_size, dwc_otg_module_params.data_fifo_size, int, 0444)
MODULE_PARM_DESC (data_fifo_size,"Total number of words in the data FIFO memory 32-32768")
module_param_named (dev_rx_fifo_size, dwc_otg_module_params.dev_rx_fifo_size, int, 0444)
MODULE_PARM_DESC (dev_rx_fifo_size,"Number of words in the Rx FIFO 16-32768")
module_param_named (dev_nperio_tx_fifo_size, dwc_otg_module_params.dev_nperio_tx_fifo_size, int, 0444)
MODULE_PARM_DESC (dev_nperio_tx_fifo_size,"Number of words in the non-periodic Tx FIFO 16-32768")
module_param_named (dev_perio_tx_fifo_size_1, dwc_otg_module_params.dev_perio_tx_fifo_size[0], int, 0444)
MODULE_PARM_DESC (dev_perio_tx_fifo_size_1,"Number of words in the periodic Tx FIFO 4-768")
module_param_named (dev_perio_tx_fifo_size_2, dwc_otg_module_params.dev_perio_tx_fifo_size[1], int, 0444)
MODULE_PARM_DESC (dev_perio_tx_fifo_size_2,"Number of words in the periodic Tx FIFO 4-768")
module_param_named (dev_perio_tx_fifo_size_3, dwc_otg_module_params.dev_perio_tx_fifo_size[2], int, 0444)
MODULE_PARM_DESC (dev_perio_tx_fifo_size_3,"Number of words in the periodic Tx FIFO 4-768")
module_param_named (dev_perio_tx_fifo_size_4, dwc_otg_module_params.dev_perio_tx_fifo_size[3], int, 0444)
MODULE_PARM_DESC (dev_perio_tx_fifo_size_4,"Number of words in the periodic Tx FIFO 4-768")
module_param_named (dev_perio_tx_fifo_size_5, dwc_otg_module_params.dev_perio_tx_fifo_size[4], int, 0444)
MODULE_PARM_DESC (dev_perio_tx_fifo_size_5,"Number of words in the periodic Tx FIFO 4-768")
module_param_named (dev_perio_tx_fifo_size_6, dwc_otg_module_params.dev_perio_tx_fifo_size[5], int, 0444)
MODULE_PARM_DESC (dev_perio_tx_fifo_size_6,"Number of words in the periodic Tx FIFO 4-768")
module_param_named (dev_perio_tx_fifo_size_7, dwc_otg_module_params.dev_perio_tx_fifo_size[6], int, 0444)
MODULE_PARM_DESC (dev_perio_tx_fifo_size_7,"Number of words in the periodic Tx FIFO 4-768")
module_param_named (dev_perio_tx_fifo_size_8, dwc_otg_module_params.dev_perio_tx_fifo_size[7], int, 0444)
MODULE_PARM_DESC (dev_perio_tx_fifo_size_8,"Number of words in the periodic Tx FIFO 4-768")
module_param_named (dev_perio_tx_fifo_size_9, dwc_otg_module_params.dev_perio_tx_fifo_size[8], int, 0444)
MODULE_PARM_DESC (dev_perio_tx_fifo_size_9,"Number of words in the periodic Tx FIFO 4-768")
module_param_named (dev_perio_tx_fifo_size_10, dwc_otg_module_params.dev_perio_tx_fifo_size[9], int, 0444)
MODULE_PARM_DESC (dev_perio_tx_fifo_size_10,"Number of words in the periodic Tx FIFO 4-768")
module_param_named (dev_perio_tx_fifo_size_11, dwc_otg_module_params.dev_perio_tx_fifo_size[10], int, 0444)
MODULE_PARM_DESC (dev_perio_tx_fifo_size_11,"Number of words in the periodic Tx FIFO 4-768")
module_param_named (dev_perio_tx_fifo_size_12, dwc_otg_module_params.dev_perio_tx_fifo_size[11], int, 0444)
MODULE_PARM_DESC (dev_perio_tx_fifo_size_12,"Number of words in the periodic Tx FIFO 4-768")
module_param_named (dev_perio_tx_fifo_size_13, dwc_otg_module_params.dev_perio_tx_fifo_size[12], int, 0444)
MODULE_PARM_DESC (dev_perio_tx_fifo_size_13,"Number of words in the periodic Tx FIFO 4-768")
module_param_named (dev_perio_tx_fifo_size_14, dwc_otg_module_params.dev_perio_tx_fifo_size[13], int, 0444)
MODULE_PARM_DESC (dev_perio_tx_fifo_size_14,"Number of words in the periodic Tx FIFO 4-768")
module_param_named (dev_perio_tx_fifo_size_15, dwc_otg_module_params.dev_perio_tx_fifo_size[14], int, 0444)
MODULE_PARM_DESC (dev_perio_tx_fifo_size_15,"Number of words in the periodic Tx FIFO 4-768")
module_param_named (host_rx_fifo_size, dwc_otg_module_params.host_rx_fifo_size, int, 0444)
MODULE_PARM_DESC (host_rx_fifo_size,"Number of words in the Rx FIFO 16-32768")
module_param_named (host_nperio_tx_fifo_size, dwc_otg_module_params.host_nperio_tx_fifo_size, int, 0444)
MODULE_PARM_DESC (host_nperio_tx_fifo_size,"Number of words in the non-periodic Tx FIFO 16-32768")
module_param_named (host_perio_tx_fifo_size, dwc_otg_module_params.host_perio_tx_fifo_size, int, 0444)
MODULE_PARM_DESC (host_perio_tx_fifo_size,"Number of words in the host periodic Tx FIFO 16-32768")
module_param_named (max_transfer_size, dwc_otg_module_params.max_transfer_size, int, 0444)
 MODULE_PARM_DESC (max_transfer_size,"The maximum transfer size supported in bytes 2047-65535")
module_param_named (max_packet_count, dwc_otg_module_params.max_packet_count, int, 0444)
MODULE_PARM_DESC (max_packet_count,"The maximum number of packets in a transfer 15-511")
module_param_named (host_channels, dwc_otg_module_params.host_channels, int, 0444)
MODULE_PARM_DESC (host_channels,"The number of host channel registers to use 1-16")
module_param_named (dev_endpoints, dwc_otg_module_params.dev_endpoints, int, 0444)
MODULE_PARM_DESC (dev_endpoints,"The number of endpoints in addition to EP0 available for device mode 1-15")
module_param_named (phy_type, dwc_otg_module_params.phy_type, int, 0444)
MODULE_PARM_DESC (phy_type,"0=Reserved 1=UTMI+ 2=ULPI")
module_param_named (phy_utmi_width, dwc_otg_module_params.phy_utmi_width, int, 0444)
MODULE_PARM_DESC (phy_utmi_width,"Specifies the UTMI+ Data Width 8 or 16 bits")
module_param_named (phy_ulpi_ddr, dwc_otg_module_params.phy_ulpi_ddr, int, 0444)
MODULE_PARM_DESC (phy_ulpi_ddr,"ULPI at double or single data rate 0=Single 1=Double")
module_param_named (phy_ulpi_ext_vbus, dwc_otg_module_params.phy_ulpi_ext_vbus, int, 0444)
MODULE_PARM_DESC (phy_ulpi_ext_vbus,"ULPI PHY using internal or external vbus 0=Internal")
module_param_named (i2c_enable, dwc_otg_module_params.i2c_enable, int, 0444)
MODULE_PARM_DESC (i2c_enable,"FS PHY Interface")
module_param_named (ulpi_fs_ls, dwc_otg_module_params.ulpi_fs_ls, int, 0444)
MODULE_PARM_DESC (ulpi_fs_ls,"ULPI PHY FS/LS mode only")
module_param_named (ts_dline, dwc_otg_module_params.ts_dline, int, 0444)
MODULE_PARM_DESC (ts_dline,"Term select Dline pulsing for all PHYs")
module_param_named (debug, g_dbg_lvl, int, 0444)
MODULE_PARM_DESC (debug,"")
module_param_named (en_multiple_tx_fifo, dwc_otg_module_params.en_multiple_tx_fifo, int, 0444)
MODULE_PARM_DESC (en_multiple_tx_fifo,"Dedicated Non Periodic Tx FIFOs 0=disabled 1=enabled")
module_param_named (dev_tx_fifo_size_1, dwc_otg_module_params.dev_tx_fifo_size[0], int, 0444)
MODULE_PARM_DESC (dev_tx_fifo_size_1,"Number of words in the Tx FIFO 4-768")
module_param_named (dev_tx_fifo_size_2, dwc_otg_module_params.dev_tx_fifo_size[1], int, 0444)
MODULE_PARM_DESC (dev_tx_fifo_size_2,"Number of words in the Tx FIFO 4-768")
module_param_named (dev_tx_fifo_size_3, dwc_otg_module_params.dev_tx_fifo_size[2], int, 0444)
MODULE_PARM_DESC (dev_tx_fifo_size_3,"Number of words in the Tx FIFO 4-768")
module_param_named (dev_tx_fifo_size_4, dwc_otg_module_params.dev_tx_fifo_size[3], int, 0444)
MODULE_PARM_DESC (dev_tx_fifo_size_4,"Number of words in the Tx FIFO 4-768")
module_param_named (dev_tx_fifo_size_5, dwc_otg_module_params.dev_tx_fifo_size[4], int, 0444)
MODULE_PARM_DESC (dev_tx_fifo_size_5,"Number of words in the Tx FIFO 4-768")
module_param_named (dev_tx_fifo_size_6, dwc_otg_module_params.dev_tx_fifo_size[5], int, 0444)
MODULE_PARM_DESC (dev_tx_fifo_size_6,"Number of words in the Tx FIFO 4-768")
module_param_named (dev_tx_fifo_size_7, dwc_otg_module_params.dev_tx_fifo_size[6], int, 0444)
MODULE_PARM_DESC (dev_tx_fifo_size_7,"Number of words in the Tx FIFO 4-768")
module_param_named (dev_tx_fifo_size_8, dwc_otg_module_params.dev_tx_fifo_size[7], int, 0444)
MODULE_PARM_DESC (dev_tx_fifo_size_8,"Number of words in the Tx FIFO 4-768")
module_param_named (dev_tx_fifo_size_9, dwc_otg_module_params.dev_tx_fifo_size[8], int, 0444)
MODULE_PARM_DESC (dev_tx_fifo_size_9,"Number of words in the Tx FIFO 4-768")
module_param_named (dev_tx_fifo_size_10, dwc_otg_module_params.dev_tx_fifo_size[9], int, 0444)
MODULE_PARM_DESC (dev_tx_fifo_size_10,"Number of words in the Tx FIFO 4-768")
module_param_named (dev_tx_fifo_size_11, dwc_otg_module_params.dev_tx_fifo_size[10], int, 0444)
MODULE_PARM_DESC (dev_tx_fifo_size_11,"Number of words in the Tx FIFO 4-768")
module_param_named (dev_tx_fifo_size_12, dwc_otg_module_params.dev_tx_fifo_size[11], int, 0444)
MODULE_PARM_DESC (dev_tx_fifo_size_12,"Number of words in the Tx FIFO 4-768")
module_param_named (dev_tx_fifo_size_13, dwc_otg_module_params.dev_tx_fifo_size[12], int, 0444)
MODULE_PARM_DESC (dev_tx_fifo_size_13,"Number of words in the Tx FIFO 4-768")
module_param_named (dev_tx_fifo_size_14, dwc_otg_module_params.dev_tx_fifo_size[13], int, 0444)
MODULE_PARM_DESC (dev_tx_fifo_size_14,"Number of words in the Tx FIFO 4-768")
module_param_named (dev_tx_fifo_size_15, dwc_otg_module_params.dev_tx_fifo_size[14], int, 0444)
MODULE_PARM_DESC (dev_tx_fifo_size_15,"Number of words in the Tx FIFO 4-768")
module_param_named (thr_ctl, dwc_otg_module_params.thr_ctl, int, 0444)
MODULE_PARM_DESC (thr_ctl,"Thresholding enable flag bit 0 - non ISO Tx thr., 1 - ISO Tx thr., 2 - Rx thr.- bit 0=disabled 1=enabled")
module_param_named (tx_thr_length, dwc_otg_module_params.tx_thr_length, int, 0444)
MODULE_PARM_DESC (tx_thr_length,"Tx Threshold length in 32 bit DWORDs")
module_param_named (rx_thr_length, dwc_otg_module_params.rx_thr_length, int, 0444)
MODULE_PARM_DESC (rx_thr_length,"Rx Threshold length in 32 bit DWORDs")
module_param_named (pti_enable, dwc_otg_module_params.pti_enable, int, 0444)
module_param_named (mpi_enable, dwc_otg_module_params.mpi_enable, int, 0444)
module_param_named (lpm_enable, dwc_otg_module_params.lpm_enable, int, 0444)
MODULE_PARM_DESC (lpm_enable,"LPM Enable 0=LPM Disabled 1=LPM Enabled")
module_param_named (ic_usb_cap, dwc_otg_module_params.ic_usb_cap, int, 0444)
MODULE_PARM_DESC (ic_usb_cap,"IC_USB Capability 0=IC_USB Disabled 1=IC_USB Enabled")
module_param_named (ahb_thr_ratio, dwc_otg_module_params.ahb_thr_ratio, int, 0444)
MODULE_PARM_DESC (ahb_thr_ratio,"AHB Threshold Ratio")

Variables

+static const char dwc_driver_name [] = "dwc_otg"
+static struct dwc_otg_driver_module_params dwc_otg_module_params
+uint32_t g_dbg_lvl = 0
 The Debug Level bit-mask variable.
+


Detailed Description

+The dwc_otg_driver module provides the initialization and cleanup entry points for the DWC_otg driver. +

+This module will be dynamically installed after Linux is booted using the insmod command. When the module is installed, the dwc_otg_driver_init function is called. When the module is removed (using rmmod), the dwc_otg_driver_cleanup function is called.

+This module also defines a data structure for the dwc_otg_driver, which is used in conjunction with the standard ARM lm_device structure. These structures allow the OTG driver to comply with the standard Linux driver model in which devices and drivers are registered with a bus driver. This has the benefit that Linux can expose attributes of the driver and device in its special sysfs file system. Users can then read or write files in this file system to perform diagnostics on the driver components or the device. +

+Definition in file dwc_otg_driver.c.


Function Documentation

+ +
+
+ + + + + + + + +
int hcd_init (  ) 
+
+
+ +

+Initializes the HCD. +

+This function allocates memory for and initializes the static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the USB bus with the core and calls the hc_driver->start() function. It returns a negative error on failure. +

+Definition at line 327 of file dwc_otg_hcd_linux.c. +

+

+ +

+
+ + + + + + + + +
void hcd_remove (  ) 
+
+
+ +

+Removes the HCD. +

+Frees memory and resources associated with the HCD and deregisters the bus. +

+Definition at line 417 of file dwc_otg_hcd_linux.c. +

+

+ +

+
+ + + + + + + + +
static void dwc_otg_driver_remove (  )  [static]
+
+
+ +

+This function is called when a lm_device is unregistered with the dwc_otg_driver. +

+This happens, for example, when the rmmod command is executed. The device may or may not be electrically present. If it is present, the driver stops device processing. Any resources used on behalf of this device are freed.

+

Parameters:
+ + +
_dev 
+
+ +

+Definition at line 525 of file dwc_otg_driver.c. +

+

+ +

+
+ + + + + + + + +
static int dwc_otg_driver_probe (  )  [static]
+
+
+ +

+This function is called when an lm_device is bound to a dwc_otg_driver. +

+It creates the driver components required to control the device (CIL, HCD, and PCD) and it initializes the device. The driver components are stored in a dwc_otg_device structure. A reference to the dwc_otg_device is saved in the lm_device. This allows the driver to access the dwc_otg_device structure on subsequent calls to driver methods for this device.

+

Parameters:
+ + +
_dev Bus device
+
+ +

+Definition at line 608 of file dwc_otg_driver.c. +

+

+ +

+
+ + + + + + + + + +
static int __init dwc_otg_driver_init (void   )  [static]
+
+
+ +

+This function is called when the dwc_otg_driver is installed with the insmod command. +

+It registers the dwc_otg_driver structure with the appropriate bus driver. This will cause the dwc_otg_driver_probe function to be called. In addition, the bus driver will automatically expose attributes defined for the device and driver in the special sysfs file system.

+

Returns:
+ +

+Definition at line 866 of file dwc_otg_driver.c. +

+

+ +

+
+ + + + + + + + + +
static void __exit dwc_otg_driver_cleanup (void   )  [static]
+
+
+ +

+This function is called when the driver is removed from the kernel with the rmmod command. +

+The driver unregisters itself with its bus driver. +

+Definition at line 899 of file dwc_otg_driver.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
MODULE_PARM_DESC (max_transfer_size ,
"The maximum transfer size supported in bytes 2047-65535"  
)
+
+
+ +

+

Todo:
Set the max to 512K, modify checks
+ +
+

+


Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__driver_8h-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__driver_8h-source.html new file mode 100644 index 000000000000..5557004b7e19 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__driver_8h-source.html @@ -0,0 +1,110 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_driver.h Source File + + + + + + +

dwc_otg_driver.h

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.h $
+00003  * $Revision: #16 $
+00004  * $Date: 2009/04/03 $
+00005  * $Change: 1225160 $
+00006  *
+00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009  * otherwise expressly agreed to in writing between Synopsys and you.
+00010  * 
+00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012  * any End User Software License Agreement or Agreement for Licensed Product
+00013  * with Synopsys or any supplement thereto. You are permitted to use and
+00014  * redistribute this Software in source and binary forms, with or without
+00015  * modification, provided that redistributions of source code must retain this
+00016  * notice. You may not view, use, disclose, copy or distribute this file or
+00017  * any information contained herein except pursuant to this license grant from
+00018  * Synopsys. If you do not agree with this notice, including the disclaimer
+00019  * below, then you are not authorized to use the Software.
+00020  * 
+00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031  * DAMAGE.
+00032  * ========================================================================== */
+00033 
+00034 #ifndef __DWC_OTG_DRIVER_H__
+00035 #define __DWC_OTG_DRIVER_H__
+00036 
+00040 #include "dwc_otg_core_if.h"
+00041 
+00042 /* Type declarations */
+00043 struct dwc_otg_pcd;
+00044 struct dwc_otg_hcd;
+00045 
+00046 #ifdef  PCI_INTERFACE
+00047 #include <linux/pci.h>
+00048 #endif
+00049 
+00050 
+00051 
+00056 typedef struct dwc_otg_device {
+00058         void *base;
+00059 
+00060 #ifdef LM_INTERFACE
+00061         struct lm_device *lmdev;
+00062 #elif  PCI_INTERFACE
+00063         int rsrc_start;
+00064         int rsrc_len;
+00065 #endif
+00066 
+00068         dwc_otg_core_if_t *core_if;
+00069 
+00071         uint32_t reg_offset;
+00072 
+00074         struct dwc_otg_pcd *pcd;
+00075 
+00077         struct dwc_otg_hcd *hcd;
+00078 
+00080         uint8_t common_irq_installed;
+00081 
+00082 } dwc_otg_device_t;
+00083 
+00084 /*We must clear S3C24XX_EINTPEND external interrupt register 
+00085  * because after clearing in this register trigerred IRQ from 
+00086  * H/W core in kernel interrupt can be occured again before OTG
+00087  * handlers clear all IRQ sources of Core registers because of
+00088  * timing latencies and Low Level IRQ Type.
+00089  */
+00090 #ifdef CONFIG_MACH_IPMATE
+00091 #define  S3C2410X_CLEAR_EINTPEND()   \
+00092 do { \
+00093         __raw_writel(1UL << 11,S3C24XX_EINTPEND); \
+00094 } while (0)
+00095 #else
+00096 #define  S3C2410X_CLEAR_EINTPEND()   do { } while (0)
+00097 #endif
+00098 
+00099 #endif
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__driver_8h.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__driver_8h.html new file mode 100644 index 000000000000..c2914c1731d5 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__driver_8h.html @@ -0,0 +1,50 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_driver.h File Reference + + + + + + +

dwc_otg_driver.h File Reference

This file contains the interface to the Linux driver. More... +

+#include "dwc_otg_core_if.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + +

Data Structures

struct  dwc_otg_device
 This structure is a wrapper that encapsulates the driver components used to manage a single DWC_otg controller. More...

Defines

+#define S3C2410X_CLEAR_EINTPEND()   do { } while (0)

Typedefs

+typedef dwc_otg_device dwc_otg_device_t
 This structure is a wrapper that encapsulates the driver components used to manage a single DWC_otg controller.
+


Detailed Description

+This file contains the interface to the Linux driver. +

+ +

+Definition in file dwc_otg_driver.h.


Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd_8c-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd_8c-source.html new file mode 100644 index 000000000000..6b48db3028fb --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd_8c-source.html @@ -0,0 +1,2946 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hcd.c Source File + + + + + + +

dwc_otg_hcd.c

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.c $
+00003  * $Revision: #87 $
+00004  * $Date: 2009/04/23 $
+00005  * $Change: 1239143 $
+00006  *
+00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009  * otherwise expressly agreed to in writing between Synopsys and you.
+00010  *
+00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012  * any End User Software License Agreement or Agreement for Licensed Product
+00013  * with Synopsys or any supplement thereto. You are permitted to use and
+00014  * redistribute this Software in source and binary forms, with or without
+00015  * modification, provided that redistributions of source code must retain this
+00016  * notice. You may not view, use, disclose, copy or distribute this file or
+00017  * any information contained herein except pursuant to this license grant from
+00018  * Synopsys. If you do not agree with this notice, including the disclaimer
+00019  * below, then you are not authorized to use the Software.
+00020  *
+00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031  * DAMAGE.
+00032  * ========================================================================== */
+00033 #ifndef DWC_DEVICE_ONLY
+00034 
+00042 #include "dwc_otg_hcd.h"
+00043 #include "dwc_otg_regs.h"
+00044                 
+00045 dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void)
+00046 {
+00047         return dwc_alloc(sizeof(dwc_otg_hcd_t));
+00048 }
+00049 
+00054 void dwc_otg_hcd_connect_timeout(void *ptr)
+00055 {
+00056         DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, ptr);
+00057         DWC_PRINTF("Connect Timeout\n");
+00058         __DWC_ERROR("Device Not Connected/Responding\n");
+00059 }
+00060 
+00061 #ifdef DEBUG
+00062 static void dump_channel_info(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+00063 {
+00064         if (qh->channel != NULL) {
+00065                 dwc_hc_t *hc = qh->channel;
+00066                 dwc_list_link_t *item;
+00067                 dwc_otg_qh_t *qh_item;
+00068                 int num_channels = hcd->core_if->core_params->host_channels;
+00069                 int i;
+00070 
+00071                 dwc_otg_hc_regs_t *hc_regs;
+00072                 hcchar_data_t hcchar;
+00073                 hcsplt_data_t hcsplt;
+00074                 hctsiz_data_t hctsiz;
+00075                 uint32_t hcdma;
+00076 
+00077                 hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num];
+00078                 hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+00079                 hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt);
+00080                 hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
+00081                 hcdma = dwc_read_reg32(&hc_regs->hcdma);
+00082 
+00083                 DWC_PRINTF("  Assigned to channel %p:\n", hc);
+00084                 DWC_PRINTF("    hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32,
+00085                            hcsplt.d32);
+00086                 DWC_PRINTF("    hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32,
+00087                            hcdma);
+00088                 DWC_PRINTF("    dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
+00089                            hc->dev_addr, hc->ep_num, hc->ep_is_in);
+00090                 DWC_PRINTF("    ep_type: %d\n", hc->ep_type);
+00091                 DWC_PRINTF("    max_packet: %d\n", hc->max_packet);
+00092                 DWC_PRINTF("    data_pid_start: %d\n", hc->data_pid_start);
+00093                 DWC_PRINTF("    xfer_started: %d\n", hc->xfer_started);
+00094                 DWC_PRINTF("    halt_status: %d\n", hc->halt_status);
+00095                 DWC_PRINTF("    xfer_buff: %p\n", hc->xfer_buff);
+00096                 DWC_PRINTF("    xfer_len: %d\n", hc->xfer_len);
+00097                 DWC_PRINTF("    qh: %p\n", hc->qh);
+00098                 DWC_PRINTF("  NP inactive sched:\n");
+00099                 DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_inactive) {
+00100                         qh_item =
+00101                             DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
+00102                         DWC_PRINTF("    %p\n", qh_item);
+00103                 }
+00104                 DWC_PRINTF("  NP active sched:\n");
+00105                 DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_active) {
+00106                         qh_item =
+00107                             DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
+00108                         DWC_PRINTF("    %p\n", qh_item);
+00109                 }
+00110                 DWC_PRINTF("  Channels: \n");
+00111                 for (i = 0; i < num_channels; i++) {
+00112                         dwc_hc_t *hc = hcd->hc_ptr_array[i];
+00113                         DWC_PRINTF("    %2d: %p\n", i, hc);
+00114                 }
+00115         }
+00116 }
+00117 #endif                          /* DEBUG */
+00118 
+00123 static void hcd_start_func(void *_vp)
+00124 {
+00125         dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) _vp;
+00126 
+00127         DWC_DEBUGPL(DBG_HCDV, "%s() %p\n", __func__, hcd);
+00128         if (hcd) {
+00129                 hcd->fops->start(hcd);
+00130         }
+00131 }
+00132 
+00133 static void del_xfer_timers(dwc_otg_hcd_t * hcd)
+00134 {
+00135 #ifdef DEBUG
+00136         int i;
+00137         int num_channels = hcd->core_if->core_params->host_channels;
+00138         for (i = 0; i < num_channels; i++) {
+00139                 DWC_TIMER_CANCEL(hcd->core_if->hc_xfer_timer[i]);
+00140         }
+00141 #endif
+00142 }
+00143 
+00144 static void del_timers(dwc_otg_hcd_t * hcd)
+00145 {
+00146         del_xfer_timers(hcd);
+00147         DWC_TIMER_CANCEL(hcd->conn_timer);
+00148 }
+00149 
+00154 static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
+00155 {
+00156         dwc_list_link_t *qh_item;
+00157         dwc_otg_qh_t *qh;
+00158         dwc_otg_qtd_t *qtd, *qtd_tmp;
+00159 
+00160         DWC_LIST_FOREACH(qh_item, qh_list) {
+00161                 qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
+00162                 DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp,
+00163                                          &qh->qtd_list, qtd_list_entry) {
+00164                         qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
+00165                         if (qtd->urb != NULL) {
+00166                                 hcd->fops->complete(hcd, qtd->urb->priv,
+00167                                                     qtd->urb,
+00168                                                     -DWC_E_TIMEOUT);
+00169                                 dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
+00170                         }
+00171 
+00172                 }
+00173         }
+00174 }
+00175 
+00182 static void kill_all_urbs(dwc_otg_hcd_t * hcd)
+00183 {
+00184         kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_inactive);
+00185         kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_active);
+00186         kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_inactive);
+00187         kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_ready);
+00188         kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_assigned);
+00189         kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_queued);
+00190 }
+00191 
+00198 static void dwc_otg_hcd_start_connect_timer(dwc_otg_hcd_t * hcd)
+00199 {
+00200         DWC_TIMER_SCHEDULE(hcd->conn_timer, 10000 /* 10 secs */ );
+00201 }
+00202 
+00208 static int32_t dwc_otg_hcd_session_start_cb(void *p)
+00209 {
+00210         dwc_otg_hcd_t *dwc_otg_hcd;
+00211         DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
+00212         dwc_otg_hcd = p;
+00213         dwc_otg_hcd_start_connect_timer(dwc_otg_hcd);
+00214         return 1;
+00215 }
+00216 
+00223 static int32_t dwc_otg_hcd_start_cb(void *p)
+00224 {
+00225         dwc_otg_hcd_t *dwc_otg_hcd = p;
+00226         dwc_otg_core_if_t *core_if;
+00227         hprt0_data_t hprt0;
+00228 
+00229         core_if = dwc_otg_hcd->core_if;
+00230 
+00231         if (core_if->op_state == B_HOST) {
+00232                 /*
+00233                  * Reset the port.  During a HNP mode switch the reset
+00234                  * needs to occur within 1ms and have a duration of at
+00235                  * least 50ms.
+00236                  */
+00237                 hprt0.d32 = dwc_otg_read_hprt0(core_if);
+00238                 hprt0.b.prtrst = 1;
+00239                 dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+00240         }
+00241         DWC_WORKQ_SCHEDULE_DELAYED(core_if->wq_otg,
+00242                                    hcd_start_func, dwc_otg_hcd, 50,
+00243                                    "start hcd");
+00244 
+00245         return 1;
+00246 }
+00247 
+00253 static int32_t dwc_otg_hcd_disconnect_cb(void *p)
+00254 {
+00255         gintsts_data_t intr;
+00256         dwc_otg_hcd_t *dwc_otg_hcd = p;
+00257 
+00258         /*
+00259          * Set status flags for the hub driver.
+00260          */
+00261         dwc_otg_hcd->flags.b.port_connect_status_change = 1;
+00262         dwc_otg_hcd->flags.b.port_connect_status = 0;
+00263 
+00264         /*
+00265          * Shutdown any transfers in process by clearing the Tx FIFO Empty
+00266          * interrupt mask and status bits and disabling subsequent host
+00267          * channel interrupts.
+00268          */
+00269         intr.d32 = 0;
+00270         intr.b.nptxfempty = 1;
+00271         intr.b.ptxfempty = 1;
+00272         intr.b.hcintr = 1;
+00273         dwc_modify_reg32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk,
+00274                          intr.d32, 0);
+00275         dwc_modify_reg32(&dwc_otg_hcd->core_if->core_global_regs->gintsts,
+00276                          intr.d32, 0);
+00277 
+00278         del_timers(dwc_otg_hcd);
+00279 
+00280         /*
+00281          * Turn off the vbus power only if the core has transitioned to device
+00282          * mode. If still in host mode, need to keep power on to detect a
+00283          * reconnection.
+00284          */
+00285         if (dwc_otg_is_device_mode(dwc_otg_hcd->core_if)) {
+00286                 if (dwc_otg_hcd->core_if->op_state != A_SUSPEND) {
+00287                         hprt0_data_t hprt0 = {.d32 = 0 };
+00288                         DWC_PRINTF("Disconnect: PortPower off\n");
+00289                         hprt0.b.prtpwr = 0;
+00290                         dwc_write_reg32(dwc_otg_hcd->core_if->host_if->hprt0,
+00291                                         hprt0.d32);
+00292                 }
+00293 
+00294                 dwc_otg_disable_host_interrupts(dwc_otg_hcd->core_if);
+00295         }
+00296 
+00297         /* Respond with an error status to all URBs in the schedule. */
+00298         kill_all_urbs(dwc_otg_hcd);
+00299 
+00300         if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) {
+00301                 /* Clean up any host channels that were in use. */
+00302                 int num_channels;
+00303                 int i;
+00304                 dwc_hc_t *channel;
+00305                 dwc_otg_hc_regs_t *hc_regs;
+00306                 hcchar_data_t hcchar;
+00307 
+00308                 num_channels = dwc_otg_hcd->core_if->core_params->host_channels;
+00309 
+00310                 if (!dwc_otg_hcd->core_if->dma_enable) {
+00311                         /* Flush out any channel requests in slave mode. */
+00312                         for (i = 0; i < num_channels; i++) {
+00313                                 channel = dwc_otg_hcd->hc_ptr_array[i];
+00314                                 if (DWC_CIRCLEQ_EMPTY_ENTRY
+00315                                     (channel, hc_list_entry)) {
+00316                                         hc_regs =
+00317                                             dwc_otg_hcd->core_if->host_if->
+00318                                             hc_regs[i];
+00319                                         hcchar.d32 =
+00320                                             dwc_read_reg32(&hc_regs->hcchar);
+00321                                         if (hcchar.b.chen) {
+00322                                                 hcchar.b.chen = 0;
+00323                                                 hcchar.b.chdis = 1;
+00324                                                 hcchar.b.epdir = 0;
+00325                                                 dwc_write_reg32(&hc_regs->
+00326                                                                 hcchar,
+00327                                                                 hcchar.d32);
+00328                                         }
+00329                                 }
+00330                         }
+00331                 }
+00332 
+00333                 for (i = 0; i < num_channels; i++) {
+00334                         channel = dwc_otg_hcd->hc_ptr_array[i];
+00335                         if (DWC_CIRCLEQ_EMPTY_ENTRY(channel, hc_list_entry)) {
+00336                                 hc_regs =
+00337                                     dwc_otg_hcd->core_if->host_if->hc_regs[i];
+00338                                 hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+00339                                 if (hcchar.b.chen) {
+00340                                         /* Halt the channel. */
+00341                                         hcchar.b.chdis = 1;
+00342                                         dwc_write_reg32(&hc_regs->hcchar,
+00343                                                         hcchar.d32);
+00344                                 }
+00345 
+00346                                 dwc_otg_hc_cleanup(dwc_otg_hcd->core_if,
+00347                                                    channel);
+00348                                 DWC_CIRCLEQ_INSERT_TAIL(&dwc_otg_hcd->
+00349                                                         free_hc_list, channel,
+00350                                                         hc_list_entry);
+00351                                 /* 
+00352                                  * Added for Descriptor DMA to prevent channel double cleanup 
+00353                                  * in release_channel_ddma(). Which called from ep_disable
+00354                                  * when device disconnect.
+00355                                  */                     
+00356                                 channel->qh = NULL;                     
+00357                         }
+00358                 }
+00359         }
+00360 
+00361         if (dwc_otg_hcd->fops->disconnect) {
+00362                 dwc_otg_hcd->fops->disconnect(dwc_otg_hcd);
+00363         }
+00364 
+00365         return 1;
+00366 }
+00367 
+00373 static int32_t dwc_otg_hcd_stop_cb(void *p)
+00374 {
+00375         dwc_otg_hcd_t *dwc_otg_hcd = p;
+00376 
+00377         DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p);
+00378         dwc_otg_hcd_stop(dwc_otg_hcd);
+00379         return 1;
+00380 }
+00381 
+00382 #ifdef CONFIG_USB_DWC_OTG_LPM
+00383 
+00388 static int dwc_otg_hcd_sleep_cb(void *p)
+00389 {
+00390         dwc_otg_hcd_t *hcd = p;
+00391 
+00392         dwc_otg_hcd_free_hc_from_lpm(hcd);
+00393 
+00394         return 0;
+00395 }
+00396 #endif
+00397 
+00403 static int dwc_otg_hcd_rem_wakeup_cb(void *p)
+00404 {
+00405         dwc_otg_hcd_t *hcd = p;
+00406 
+00407         if (hcd->core_if->lx_state == DWC_OTG_L2) {
+00408                 hcd->flags.b.port_suspend_change = 1;
+00409         }
+00410 #ifdef CONFIG_USB_DWC_OTG_LPM
+00411         else {
+00412                 hcd->flags.b.port_l1_change = 1;
+00413         }
+00414 #endif
+00415         return 0;
+00416 }
+00417 
+00422 void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd)
+00423 {
+00424         hprt0_data_t hprt0 = {.d32 = 0 };
+00425 
+00426         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n");
+00427 
+00428         /*
+00429          * The root hub should be disconnected before this function is called.
+00430          * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)
+00431          * and the QH lists (via ..._hcd_endpoint_disable).
+00432          */
+00433 
+00434         /* Turn off all host-specific interrupts. */
+00435         dwc_otg_disable_host_interrupts(hcd->core_if);
+00436 
+00437         /* Turn off the vbus power */
+00438         DWC_PRINTF("PortPower off\n");
+00439         hprt0.b.prtpwr = 0;
+00440         dwc_write_reg32(hcd->core_if->host_if->hprt0, hprt0.d32);
+00441         dwc_mdelay(1);
+00442 }
+00443 
+00444 int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd,
+00445                             dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle)
+00446 {
+00447         uint64_t flags;
+00448         int retval = 0;
+00449         dwc_otg_qtd_t *qtd;
+00450 
+00451         if (!hcd->flags.b.port_connect_status) {
+00452                 /* No longer connected. */
+00453                 return -DWC_E_NO_DEVICE;
+00454         }
+00455 
+00456         qtd = dwc_otg_hcd_qtd_create(dwc_otg_urb);
+00457         if (qtd == NULL) {
+00458                 DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n");
+00459                 return -DWC_E_NO_MEMORY;
+00460         }
+00461 
+00462         retval =
+00463             dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle);
+00464         if (retval < 0) {
+00465                 DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. "
+00466                           "Error status %d\n", retval);
+00467                 dwc_otg_hcd_qtd_free(qtd);
+00468         } else {
+00469                 qtd->qh = *ep_handle;
+00470         }
+00471         
+00472         if (hcd->core_if->dma_desc_enable && retval == 0) {
+00473                 dwc_otg_transaction_type_e tr_type;     
+00474                 if ((qtd->qh->ep_type == UE_BULK) && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) {
+00475                         /* Do not schedule SG transcations until qtd has URB_GIVEBACK_ASAP set */
+00476                         return 0;
+00477                 }
+00478                 DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
+00479                 tr_type = dwc_otg_hcd_select_transactions(hcd);
+00480                 if (tr_type != DWC_OTG_TRANSACTION_NONE) {
+00481                         dwc_otg_hcd_queue_transactions(hcd, tr_type);
+00482                 }
+00483                 DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
+00484         }
+00485 
+00486         return retval;
+00487 }
+00488 
+00489 int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd,
+00490                             dwc_otg_hcd_urb_t * dwc_otg_urb)
+00491 {
+00492         uint64_t flags;
+00493 
+00494         dwc_otg_qh_t *qh;
+00495         dwc_otg_qtd_t *urb_qtd;
+00496 
+00497         DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
+00498         
+00499         urb_qtd = dwc_otg_urb->qtd;
+00500         qh = urb_qtd->qh;
+00501 #ifdef DEBUG
+00502         if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
+00503                 if (urb_qtd->in_process) {
+00504                         dump_channel_info(hcd, qh);
+00505                 }
+00506         }
+00507 #endif
+00508         if (urb_qtd->in_process && qh->channel) {
+00509                 /* The QTD is in process (it has been assigned to a channel). */
+00510                 if (hcd->flags.b.port_connect_status) {
+00511                         /*
+00512                          * If still connected (i.e. in host mode), halt the
+00513                          * channel so it can be used for other transfers. If
+00514                          * no longer connected, the host registers can't be
+00515                          * written to halt the channel since the core is in
+00516                          * device mode.
+00517                          */
+00518                         dwc_otg_hc_halt(hcd->core_if, qh->channel,
+00519                                         DWC_OTG_HC_XFER_URB_DEQUEUE);
+00520                 }
+00521         }
+00522 
+00523         /*
+00524          * Free the QTD and clean up the associated QH. Leave the QH in the
+00525          * schedule if it has any remaining QTDs.
+00526          */
+00527          
+00528         if (!hcd->core_if->dma_desc_enable) {
+00529                 uint8_t b = urb_qtd->in_process;        
+00530                 dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
+00531                 if (b) {
+00532                         dwc_otg_hcd_qh_deactivate(hcd, qh, 0);
+00533                         qh->channel = NULL;
+00534                 } else if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
+00535                         dwc_otg_hcd_qh_remove(hcd, qh);
+00536                 }
+00537         }
+00538         else {
+00539                 dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh);
+00540         }
+00541         
+00542         DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
+00543 
+00544         return 0;
+00545 }
+00546 
+00547 int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
+00548                                  int retry)
+00549 {
+00550         dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
+00551         int retval = 0;
+00552         uint64_t flags;
+00553 
+00554         if (retry < 0) {
+00555                 retval = -DWC_E_INVALID;
+00556                 goto done;
+00557         }
+00558 
+00559         if (!qh) {
+00560                 goto done;
+00561         }
+00562 
+00563         DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
+00564         
+00565         while (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list) && retry) {
+00566                 DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
+00567                 retry--;
+00568                 dwc_msleep(5);
+00569                 DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
+00570         }
+00571 
+00572         dwc_otg_hcd_qh_remove(hcd, qh);
+00573         
+00574         DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
+00575         /* 
+00576          * Split dwc_otg_hcd_qh_remove_and_free() into qh_remove 
+00577          * and qh_free to prevent stack dump on dwc_dma_free() with 
+00578          * irq_disabled (spinlock_irqsave) in dwc_otg_hcd_desc_list_free() 
+00579          * and dwc_otg_hcd_frame_list_alloc().
+00580          */
+00581         dwc_otg_hcd_qh_free(hcd, qh);
+00582 
+00583       done:
+00584         return retval;
+00585 }
+00586 
+00590 static dwc_otg_cil_callbacks_t hcd_cil_callbacks = {
+00591         .start = dwc_otg_hcd_start_cb,
+00592         .stop = dwc_otg_hcd_stop_cb,
+00593         .disconnect = dwc_otg_hcd_disconnect_cb,
+00594         .session_start = dwc_otg_hcd_session_start_cb,
+00595         .resume_wakeup = dwc_otg_hcd_rem_wakeup_cb,
+00596 #ifdef CONFIG_USB_DWC_OTG_LPM
+00597         .sleep = dwc_otg_hcd_sleep_cb,
+00598 #endif
+00599         .p = 0,
+00600 };
+00601 
+00605 static void reset_tasklet_func(void *data)
+00606 {
+00607         dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t *) data;
+00608         dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
+00609         hprt0_data_t hprt0;
+00610 
+00611         DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n");
+00612 
+00613         hprt0.d32 = dwc_otg_read_hprt0(core_if);
+00614         hprt0.b.prtrst = 1;
+00615         dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+00616         dwc_mdelay(60);
+00617 
+00618         hprt0.b.prtrst = 0;
+00619         dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+00620         dwc_otg_hcd->flags.b.port_reset_change = 1;
+00621 }
+00622 
+00623 static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
+00624 {
+00625         dwc_list_link_t *item;
+00626         dwc_otg_qh_t *qh;
+00627 
+00628         if (!qh_list->next) {
+00629                 /* The list hasn't been initialized yet. */
+00630                 return;
+00631         }
+00632 
+00633         /* Ensure there are no QTDs or URBs left. */
+00634         kill_urbs_in_qh_list(hcd, qh_list);
+00635 
+00636         DWC_LIST_FOREACH(item, qh_list) {
+00637                 qh = DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry);
+00638                 dwc_otg_hcd_qh_remove_and_free(hcd, qh);
+00639         }
+00640 }
+00641 
+00646 static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd)
+00647 {
+00648         int i;
+00649 
+00650         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n");
+00651 
+00652         del_timers(dwc_otg_hcd);
+00653 
+00654         /* Free memory for QH/QTD lists */
+00655         qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive);
+00656         qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active);
+00657         qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive);
+00658         qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready);
+00659         qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned);
+00660         qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued);
+00661 
+00662         /* Free memory for the host channels. */
+00663         for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+00664                 dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i];
+00665 
+00666 #ifdef DEBUG
+00667                 if (dwc_otg_hcd->core_if->hc_xfer_timer[i]) {
+00668                         DWC_TIMER_FREE(dwc_otg_hcd->core_if->hc_xfer_timer[i]);
+00669                 }
+00670 #endif
+00671                 if (hc != NULL) {
+00672                         DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n",
+00673                                     i, hc);
+00674                         dwc_free(hc);
+00675                 }
+00676         }
+00677 
+00678         if (dwc_otg_hcd->core_if->dma_enable) {
+00679                 if (dwc_otg_hcd->status_buf_dma) {
+00680                         dwc_dma_free(DWC_OTG_HCD_STATUS_BUF_SIZE,
+00681                                      dwc_otg_hcd->status_buf,
+00682                                      dwc_otg_hcd->status_buf_dma);
+00683                 }
+00684         } else if (dwc_otg_hcd->status_buf != NULL) {
+00685                 dwc_free(dwc_otg_hcd->status_buf);
+00686         }
+00687         DWC_SPINLOCK_FREE(dwc_otg_hcd->lock);
+00688         DWC_TIMER_FREE(dwc_otg_hcd->conn_timer);
+00689         DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet);
+00690         dwc_free(dwc_otg_hcd);
+00691 }
+00692 
+00693 int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if)
+00694 {
+00695         int retval = 0;
+00696         int num_channels;
+00697         int i;
+00698         dwc_hc_t *channel;
+00699 
+00700         hcd->lock = DWC_SPINLOCK_ALLOC();
+00701 
+00702         hcd->core_if = core_if;
+00703         /* Register the HCD CIL Callbacks */
+00704         dwc_otg_cil_register_hcd_callbacks(hcd->core_if,
+00705                                            &hcd_cil_callbacks, hcd);
+00706 
+00707         /* Initialize the non-periodic schedule. */
+00708         DWC_LIST_INIT(&hcd->non_periodic_sched_inactive);
+00709         DWC_LIST_INIT(&hcd->non_periodic_sched_active);
+00710 
+00711         /* Initialize the periodic schedule. */
+00712         DWC_LIST_INIT(&hcd->periodic_sched_inactive);
+00713         DWC_LIST_INIT(&hcd->periodic_sched_ready);
+00714         DWC_LIST_INIT(&hcd->periodic_sched_assigned);
+00715         DWC_LIST_INIT(&hcd->periodic_sched_queued);
+00716 
+00717         /*
+00718          * Create a host channel descriptor for each host channel implemented
+00719          * in the controller. Initialize the channel descriptor array.
+00720          */
+00721         DWC_CIRCLEQ_INIT(&hcd->free_hc_list);
+00722         num_channels = hcd->core_if->core_params->host_channels;
+00723         DWC_MEMSET(hcd->hc_ptr_array, 0, sizeof(hcd->hc_ptr_array));
+00724         for (i = 0; i < num_channels; i++) {
+00725                 channel = dwc_alloc(sizeof(dwc_hc_t));
+00726                 if (channel == NULL) {
+00727                         retval = -DWC_E_NO_MEMORY;
+00728                         DWC_ERROR("%s: host channel allocation failed\n",
+00729                                   __func__);
+00730                         dwc_otg_hcd_free(hcd);
+00731                         goto out;
+00732                 }
+00733                 channel->hc_num = i;
+00734                 hcd->hc_ptr_array[i] = channel;
+00735 #ifdef DEBUG
+00736                 hcd->core_if->hc_xfer_timer[i] =
+00737                     DWC_TIMER_ALLOC("hc timer", hc_xfer_timeout,
+00738                                     &hcd->core_if->hc_xfer_info[i]);
+00739 #endif
+00740                 DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i,
+00741                             channel);
+00742         }
+00743 
+00744         /* Initialize the Connection timeout timer. */
+00745         hcd->conn_timer = DWC_TIMER_ALLOC("Connection timer",
+00746                                           dwc_otg_hcd_connect_timeout, 0);
+00747 
+00748         /* Initialize reset tasklet. */
+00749         hcd->reset_tasklet = DWC_TASK_ALLOC(reset_tasklet_func, hcd);
+00750 
+00751         /*
+00752          * Allocate space for storing data on status transactions. Normally no
+00753          * data is sent, but this space acts as a bit bucket. This must be
+00754          * done after usb_add_hcd since that function allocates the DMA buffer
+00755          * pool.
+00756          */
+00757         if (hcd->core_if->dma_enable) {
+00758                 hcd->status_buf =
+00759                     dwc_dma_alloc(DWC_OTG_HCD_STATUS_BUF_SIZE,
+00760                                   &hcd->status_buf_dma);
+00761         } else {
+00762                 hcd->status_buf = dwc_alloc(DWC_OTG_HCD_STATUS_BUF_SIZE);
+00763         }
+00764         if (!hcd->status_buf) {
+00765                 retval = -DWC_E_NO_MEMORY;
+00766                 DWC_ERROR("%s: status_buf allocation failed\n", __func__);
+00767                 dwc_otg_hcd_free(hcd);
+00768                 goto out;
+00769         }
+00770 
+00771         hcd->otg_port = 1;
+00772         hcd->frame_list = NULL;
+00773         hcd->frame_list_dma = 0;
+00774 out:
+00775         return retval;
+00776 }
+00777 
+00778 void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd)
+00779 {
+00780         /* Turn off all host-specific interrupts. */
+00781         dwc_otg_disable_host_interrupts(hcd->core_if);
+00782 
+00783         dwc_otg_hcd_free(hcd);
+00784 }
+00785 
+00789 static void dwc_otg_hcd_reinit(dwc_otg_hcd_t * hcd)
+00790 {
+00791         int num_channels;
+00792         int i;
+00793         dwc_hc_t *channel;
+00794         dwc_hc_t *channel_tmp;
+00795 
+00796         hcd->flags.d32 = 0;
+00797 
+00798         hcd->non_periodic_qh_ptr = &hcd->non_periodic_sched_active;
+00799         hcd->non_periodic_channels = 0;
+00800         hcd->periodic_channels = 0;
+00801 
+00802         /*
+00803          * Put all channels in the free channel list and clean up channel
+00804          * states.
+00805          */
+00806         DWC_CIRCLEQ_FOREACH_SAFE(channel, channel_tmp,
+00807                                  &hcd->free_hc_list, hc_list_entry) {
+00808                 DWC_CIRCLEQ_REMOVE(&hcd->free_hc_list, channel, hc_list_entry);
+00809         }
+00810 
+00811         num_channels = hcd->core_if->core_params->host_channels;
+00812         for (i = 0; i < num_channels; i++) {
+00813                 channel = hcd->hc_ptr_array[i];
+00814                 DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, channel,
+00815                                         hc_list_entry);
+00816                 dwc_otg_hc_cleanup(hcd->core_if, channel);
+00817         }
+00818 
+00819         /* Initialize the DWC core for host mode operation. */
+00820         dwc_otg_core_host_init(hcd->core_if);
+00821 }
+00822 
+00832 static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+00833 {
+00834         dwc_hc_t *hc;
+00835         dwc_otg_qtd_t *qtd;
+00836         dwc_otg_hcd_urb_t *urb;
+00837         void* ptr = NULL;
+00838 
+00839         DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p)\n", __func__, hcd, qh);
+00840 
+00841         hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
+00842 
+00843         /* Remove the host channel from the free list. */
+00844         DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
+00845 
+00846         qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
+00847         
+00848         urb = qtd->urb;
+00849         qh->channel = hc;
+00850         
+00851         qtd->in_process = 1;
+00852 
+00853         /*
+00854          * Use usb_pipedevice to determine device address. This address is
+00855          * 0 before the SET_ADDRESS command and the correct address afterward.
+00856          */
+00857         hc->dev_addr = dwc_otg_hcd_get_dev_addr(&urb->pipe_info);
+00858         hc->ep_num = dwc_otg_hcd_get_ep_num(&urb->pipe_info);
+00859         hc->speed = qh->dev_speed;
+00860         hc->max_packet = dwc_max_packet(qh->maxp);
+00861 
+00862         hc->xfer_started = 0;
+00863         hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS;
+00864         hc->error_state = (qtd->error_count > 0);
+00865         hc->halt_on_queue = 0;
+00866         hc->halt_pending = 0;
+00867         hc->requests = 0;
+00868 
+00869         /*
+00870          * The following values may be modified in the transfer type section
+00871          * below. The xfer_len value may be reduced when the transfer is
+00872          * started to accommodate the max widths of the XferSize and PktCnt
+00873          * fields in the HCTSIZn register.
+00874          */
+00875         hc->do_ping = qh->ping_state;
+00876         hc->ep_is_in = (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) != 0);
+00877         hc->data_pid_start = qh->data_toggle;
+00878         hc->multi_count = 1;
+00879 
+00880         if (hcd->core_if->dma_enable) {
+00881                 hc->xfer_buff = (uint8_t *) urb->dma + urb->actual_length;
+00882         
+00883                 /* For non-dword aligned case */
+00884                 if (((uint32_t)hc->xfer_buff & 0x3) && !hcd->core_if->dma_desc_enable) {
+00885                         ptr = (uint8_t *) urb->buf + urb->actual_length;
+00886                 }
+00887         } else {
+00888                 hc->xfer_buff = (uint8_t *) urb->buf + urb->actual_length;
+00889         }
+00890         hc->xfer_len = urb->length - urb->actual_length;
+00891         hc->xfer_count = 0;
+00892 
+00893         /*
+00894          * Set the split attributes
+00895          */
+00896         hc->do_split = 0;
+00897         if (qh->do_split) {
+00898                 uint32_t hub_addr, port_addr;
+00899                 hc->do_split = 1;
+00900                 hc->xact_pos = qtd->isoc_split_pos;
+00901                 hc->complete_split = qtd->complete_split;
+00902                 hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &port_addr);
+00903                 hc->hub_addr = (uint8_t) hub_addr;
+00904                 hc->port_addr = (uint8_t) port_addr;
+00905         }
+00906 
+00907         switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
+00908         case UE_CONTROL:
+00909                 hc->ep_type = DWC_OTG_EP_TYPE_CONTROL;
+00910                 switch (qtd->control_phase) {
+00911                 case DWC_OTG_CONTROL_SETUP:
+00912                         DWC_DEBUGPL(DBG_HCDV, "  Control setup transaction\n");
+00913                         hc->do_ping = 0;
+00914                         hc->ep_is_in = 0;
+00915                         hc->data_pid_start = DWC_OTG_HC_PID_SETUP;
+00916                         if (hcd->core_if->dma_enable) {
+00917                                 hc->xfer_buff = (uint8_t *) urb->setup_dma;
+00918                         } else {
+00919                                 hc->xfer_buff = (uint8_t *) urb->setup_packet;
+00920                         }
+00921                         hc->xfer_len = 8;
+00922                         ptr = NULL;
+00923                         break;
+00924                 case DWC_OTG_CONTROL_DATA:
+00925                         DWC_DEBUGPL(DBG_HCDV, "  Control data transaction\n");
+00926                         hc->data_pid_start = qtd->data_toggle;
+00927                         break;
+00928                 case DWC_OTG_CONTROL_STATUS:
+00929                         /*
+00930                          * Direction is opposite of data direction or IN if no
+00931                          * data.
+00932                          */
+00933                         DWC_DEBUGPL(DBG_HCDV, "  Control status transaction\n");
+00934                         if (urb->length == 0) {
+00935                                 hc->ep_is_in = 1;
+00936                         } else {
+00937                                 hc->ep_is_in =
+00938                                     dwc_otg_hcd_is_pipe_out(&urb->pipe_info);
+00939                         }
+00940                         if (hc->ep_is_in) {
+00941                                 hc->do_ping = 0;
+00942                         }
+00943                         
+00944                         hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
+00945 
+00946                         hc->xfer_len = 0;
+00947                         if (hcd->core_if->dma_enable) {
+00948                                 hc->xfer_buff = (uint8_t *) hcd->status_buf_dma;
+00949                         } else {
+00950                                 hc->xfer_buff = (uint8_t *) hcd->status_buf;
+00951                         }
+00952                         ptr = NULL;
+00953                         break;
+00954                 }
+00955                 break;
+00956         case UE_BULK:
+00957                 hc->ep_type = DWC_OTG_EP_TYPE_BULK;
+00958                 break;
+00959         case UE_INTERRUPT:
+00960                 hc->ep_type = DWC_OTG_EP_TYPE_INTR;
+00961                 break;
+00962         case UE_ISOCHRONOUS:
+00963                 {
+00964                         struct dwc_otg_hcd_iso_packet_desc *frame_desc;
+00965                         
+00966                         hc->ep_type = DWC_OTG_EP_TYPE_ISOC;
+00967                         
+00968                         if (hcd->core_if->dma_desc_enable)
+00969                                 break;
+00970                                 
+00971                         frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
+00972                         
+00973                         frame_desc->status = 0;
+00974                         
+00975                         if (hcd->core_if->dma_enable) {
+00976                                 hc->xfer_buff = (uint8_t *) urb->dma;
+00977                         } else {
+00978                                 hc->xfer_buff = (uint8_t *) urb->buf;
+00979                         }
+00980                         hc->xfer_buff +=
+00981                             frame_desc->offset + qtd->isoc_split_offset;
+00982                         hc->xfer_len =
+00983                             frame_desc->length - qtd->isoc_split_offset;
+00984 
+00985                         /* For non-dword aligned buffers */
+00986                         if (((uint32_t)hc->xfer_buff & 0x3) && hcd->core_if->dma_enable) {
+00987                                 ptr = (uint8_t *) urb->buf + frame_desc->offset + qtd->isoc_split_offset;
+00988                         }       
+00989                         else
+00990                             ptr = NULL;
+00991                         
+00992                         if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) {
+00993                                 if (hc->xfer_len <= 188) {
+00994                                         hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL;
+00995                                 } else {
+00996                                         hc->xact_pos =
+00997                                             DWC_HCSPLIT_XACTPOS_BEGIN;
+00998                                 }
+00999                         }
+01000                 }
+01001                 break;
+01002         }
+01003         /* non DWORD-aligned buffer case */     
+01004         if (ptr) {
+01005                 uint32_t buf_size;
+01006                 if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
+01007                         buf_size = hcd->core_if->core_params->max_transfer_size;
+01008                 } else {                                
+01009                         buf_size = 4096;
+01010                 }
+01011                 if (!qh->dw_align_buf) {
+01012                         qh->dw_align_buf = dwc_dma_alloc(buf_size,
+01013                                                          &qh->dw_align_buf_dma);
+01014                         if (!qh->dw_align_buf) {
+01015                                 DWC_ERROR("%s: Failed to allocate memory to handle "
+01016                                           "non-dword aligned buffer case\n", __func__);
+01017                                 return;
+01018                         }
+01019                 }
+01020                 if (!hc->ep_is_in) {
+01021                         dwc_memcpy(qh->dw_align_buf, ptr, hc->xfer_len);
+01022                 }
+01023                 hc->align_buff = qh->dw_align_buf_dma;
+01024         }
+01025         else {
+01026                 hc->align_buff = 0;
+01027         }
+01028 
+01029         if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
+01030             hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+01031                 /*
+01032                  * This value may be modified when the transfer is started to
+01033                  * reflect the actual transfer length.
+01034                  */
+01035                 hc->multi_count = dwc_hb_mult(qh->maxp);
+01036         }
+01037         
+01038         if (hcd->core_if->dma_desc_enable)
+01039                 hc->desc_list_addr = qh->desc_list_dma;
+01040         
+01041         dwc_otg_hc_init(hcd->core_if, hc);
+01042         hc->qh = qh;
+01043 }
+01044 
+01045 
+01055 dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd)
+01056 {
+01057         dwc_list_link_t *qh_ptr;
+01058         dwc_otg_qh_t *qh;
+01059         int num_channels;
+01060         dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE;
+01061 
+01062 #ifdef DEBUG_SOF
+01063         DWC_DEBUGPL(DBG_HCD, "  Select Transactions\n");
+01064 #endif
+01065 
+01066         /* Process entries in the periodic ready list. */
+01067         qh_ptr = DWC_LIST_FIRST(&hcd->periodic_sched_ready);
+01068 
+01069         while (qh_ptr != &hcd->periodic_sched_ready &&
+01070                !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
+01071 
+01072                 qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
+01073                 assign_and_init_hc(hcd, qh);
+01074 
+01075                 /*
+01076                  * Move the QH from the periodic ready schedule to the
+01077                  * periodic assigned schedule.
+01078                  */
+01079                 qh_ptr = DWC_LIST_NEXT(qh_ptr);
+01080                 DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
+01081                                    &qh->qh_list_entry);
+01082 
+01083                 ret_val = DWC_OTG_TRANSACTION_PERIODIC;
+01084         }
+01085 
+01086         /*
+01087          * Process entries in the inactive portion of the non-periodic
+01088          * schedule. Some free host channels may not be used if they are
+01089          * reserved for periodic transfers.
+01090          */
+01091         qh_ptr = hcd->non_periodic_sched_inactive.next;
+01092         num_channels = hcd->core_if->core_params->host_channels;
+01093         while (qh_ptr != &hcd->non_periodic_sched_inactive &&
+01094                (hcd->non_periodic_channels <
+01095                 num_channels - hcd->periodic_channels) &&
+01096                !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
+01097 
+01098                 qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
+01099 
+01100                 assign_and_init_hc(hcd, qh);
+01101 
+01102                 /*
+01103                  * Move the QH from the non-periodic inactive schedule to the
+01104                  * non-periodic active schedule.
+01105                  */
+01106                 qh_ptr = DWC_LIST_NEXT(qh_ptr);
+01107                 DWC_LIST_MOVE_HEAD(&hcd->non_periodic_sched_active,
+01108                                    &qh->qh_list_entry);
+01109 
+01110                 if (ret_val == DWC_OTG_TRANSACTION_NONE) {
+01111                         ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC;
+01112                 } else {
+01113                         ret_val = DWC_OTG_TRANSACTION_ALL;
+01114                 }
+01115 
+01116                 hcd->non_periodic_channels++;
+01117         }
+01118 
+01119         return ret_val;
+01120 }
+01139 static int queue_transaction(dwc_otg_hcd_t * hcd,
+01140                              dwc_hc_t * hc, uint16_t fifo_dwords_avail)
+01141 {
+01142         int retval;
+01143 
+01144         if (hcd->core_if->dma_enable) {
+01145                 if (hcd->core_if->dma_desc_enable) {
+01146                         if (!hc->xfer_started || (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) {       
+01147                                 dwc_otg_hcd_start_xfer_ddma(hcd, hc->qh);
+01148                                 hc->qh->ping_state = 0;
+01149                         }
+01150                 }
+01151                 else if (!hc->xfer_started) {
+01152                         dwc_otg_hc_start_transfer(hcd->core_if, hc);
+01153                         hc->qh->ping_state = 0;
+01154                 }
+01155                 retval = 0;
+01156         } else if (hc->halt_pending) {
+01157                 /* Don't queue a request if the channel has been halted. */
+01158                 retval = 0;
+01159         } else if (hc->halt_on_queue) {
+01160                 dwc_otg_hc_halt(hcd->core_if, hc, hc->halt_status);
+01161                 retval = 0;
+01162         } else if (hc->do_ping) {
+01163                 if (!hc->xfer_started) {
+01164                         dwc_otg_hc_start_transfer(hcd->core_if, hc);
+01165                 }
+01166                 retval = 0;
+01167         } else if (!hc->ep_is_in || hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
+01168                 if ((fifo_dwords_avail * 4) >= hc->max_packet) {
+01169                         if (!hc->xfer_started) {
+01170                                 dwc_otg_hc_start_transfer(hcd->core_if, hc);
+01171                                 retval = 1;
+01172                         } else {
+01173                                 retval =
+01174                                     dwc_otg_hc_continue_transfer(hcd->core_if,
+01175                                                                  hc);
+01176                         }
+01177                 } else {
+01178                         retval = -1;
+01179                 }
+01180         } else {
+01181                 if (!hc->xfer_started) {
+01182                         dwc_otg_hc_start_transfer(hcd->core_if, hc);
+01183                         retval = 1;
+01184                 } else {
+01185                         retval = dwc_otg_hc_continue_transfer(hcd->core_if, hc);
+01186                 }
+01187         }
+01188 
+01189         return retval;
+01190 }
+01191 
+01199 static void process_periodic_channels(dwc_otg_hcd_t * hcd)
+01200 {
+01201         hptxsts_data_t tx_status;
+01202         dwc_list_link_t *qh_ptr;
+01203         dwc_otg_qh_t *qh;
+01204         int status;
+01205         int no_queue_space = 0;
+01206         int no_fifo_space = 0;
+01207 
+01208         dwc_otg_host_global_regs_t *host_regs;
+01209         host_regs = hcd->core_if->host_if->host_global_regs;
+01210 
+01211         DWC_DEBUGPL(DBG_HCDV, "Queue periodic transactions\n");
+01212 #ifdef DEBUG
+01213         tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts);
+01214         DWC_DEBUGPL(DBG_HCDV,
+01215                     "  P Tx Req Queue Space Avail (before queue): %d\n",
+01216                     tx_status.b.ptxqspcavail);
+01217         DWC_DEBUGPL(DBG_HCDV, "  P Tx FIFO Space Avail (before queue): %d\n",
+01218                     tx_status.b.ptxfspcavail);
+01219 #endif
+01220 
+01221         qh_ptr = hcd->periodic_sched_assigned.next;
+01222         while (qh_ptr != &hcd->periodic_sched_assigned) {
+01223                 tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts);
+01224                 if (tx_status.b.ptxqspcavail == 0) {
+01225                         no_queue_space = 1;
+01226                         break;
+01227                 }
+01228 
+01229                 qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
+01230 
+01231                 /*
+01232                  * Set a flag if we're queuing high-bandwidth in slave mode.
+01233                  * The flag prevents any halts to get into the request queue in
+01234                  * the middle of multiple high-bandwidth packets getting queued.
+01235                  */
+01236                 if (!hcd->core_if->dma_enable && qh->channel->multi_count > 1) {
+01237                         hcd->core_if->queuing_high_bandwidth = 1;
+01238                 }
+01239                 status =
+01240                     queue_transaction(hcd, qh->channel,
+01241                                       tx_status.b.ptxfspcavail);
+01242                 if (status < 0) {
+01243                         no_fifo_space = 1;
+01244                         break;
+01245                 }
+01246 
+01247                 /*
+01248                  * In Slave mode, stay on the current transfer until there is
+01249                  * nothing more to do or the high-bandwidth request count is
+01250                  * reached. In DMA mode, only need to queue one request. The
+01251                  * controller automatically handles multiple packets for
+01252                  * high-bandwidth transfers.
+01253                  */
+01254                 if (hcd->core_if->dma_enable || status == 0 ||
+01255                     qh->channel->requests == qh->channel->multi_count) {
+01256                         qh_ptr = qh_ptr->next;
+01257                         /*
+01258                          * Move the QH from the periodic assigned schedule to
+01259                          * the periodic queued schedule.
+01260                          */
+01261                         DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_queued,
+01262                                            &qh->qh_list_entry);
+01263 
+01264                         /* done queuing high bandwidth */
+01265                         hcd->core_if->queuing_high_bandwidth = 0;
+01266                 }
+01267         }
+01268 
+01269         if (!hcd->core_if->dma_enable) {
+01270                 dwc_otg_core_global_regs_t *global_regs;
+01271                 gintmsk_data_t intr_mask = {.d32 = 0 };
+01272 
+01273                 global_regs = hcd->core_if->core_global_regs;
+01274                 intr_mask.b.ptxfempty = 1;
+01275 #ifdef DEBUG
+01276                 tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts);
+01277                 DWC_DEBUGPL(DBG_HCDV,
+01278                             "  P Tx Req Queue Space Avail (after queue): %d\n",
+01279                             tx_status.b.ptxqspcavail);
+01280                 DWC_DEBUGPL(DBG_HCDV,
+01281                             "  P Tx FIFO Space Avail (after queue): %d\n",
+01282                             tx_status.b.ptxfspcavail);
+01283 #endif
+01284                 if (!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned) ||
+01285                     no_queue_space || no_fifo_space) {
+01286                         /*
+01287                          * May need to queue more transactions as the request
+01288                          * queue or Tx FIFO empties. Enable the periodic Tx
+01289                          * FIFO empty interrupt. (Always use the half-empty
+01290                          * level to ensure that new requests are loaded as
+01291                          * soon as possible.)
+01292                          */
+01293                         dwc_modify_reg32(&global_regs->gintmsk, 0,
+01294                                          intr_mask.d32);
+01295                 } else {
+01296                         /*
+01297                          * Disable the Tx FIFO empty interrupt since there are
+01298                          * no more transactions that need to be queued right
+01299                          * now. This function is called from interrupt
+01300                          * handlers to queue more transactions as transfer
+01301                          * states change.
+01302                          */
+01303                         dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32,
+01304                                          0);
+01305                 }
+01306         }
+01307 }
+01308 
+01316 static void process_non_periodic_channels(dwc_otg_hcd_t * hcd)
+01317 {
+01318         gnptxsts_data_t tx_status;
+01319         dwc_list_link_t *orig_qh_ptr;
+01320         dwc_otg_qh_t *qh;
+01321         int status;
+01322         int no_queue_space = 0;
+01323         int no_fifo_space = 0;
+01324         int more_to_do = 0;
+01325 
+01326         dwc_otg_core_global_regs_t *global_regs =
+01327             hcd->core_if->core_global_regs;
+01328 
+01329         DWC_DEBUGPL(DBG_HCDV, "Queue non-periodic transactions\n");
+01330 #ifdef DEBUG
+01331         tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts);
+01332         DWC_DEBUGPL(DBG_HCDV,
+01333                     "  NP Tx Req Queue Space Avail (before queue): %d\n",
+01334                     tx_status.b.nptxqspcavail);
+01335         DWC_DEBUGPL(DBG_HCDV, "  NP Tx FIFO Space Avail (before queue): %d\n",
+01336                     tx_status.b.nptxfspcavail);
+01337 #endif
+01338         /*
+01339          * Keep track of the starting point. Skip over the start-of-list
+01340          * entry.
+01341          */
+01342         if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
+01343                 hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
+01344         }
+01345         orig_qh_ptr = hcd->non_periodic_qh_ptr;
+01346 
+01347         /*
+01348          * Process once through the active list or until no more space is
+01349          * available in the request queue or the Tx FIFO.
+01350          */
+01351         do {
+01352                 tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts);
+01353                 if (!hcd->core_if->dma_enable && tx_status.b.nptxqspcavail == 0) {
+01354                         no_queue_space = 1;
+01355                         break;
+01356                 }
+01357 
+01358                 qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t,
+01359                                     qh_list_entry);
+01360                 status =
+01361                     queue_transaction(hcd, qh->channel,
+01362                                       tx_status.b.nptxfspcavail);
+01363 
+01364                 if (status > 0) {
+01365                         more_to_do = 1;
+01366                 } else if (status < 0) {
+01367                         no_fifo_space = 1;
+01368                         break;
+01369                 }
+01370 
+01371                 /* Advance to next QH, skipping start-of-list entry. */
+01372                 hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
+01373                 if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) {
+01374                         hcd->non_periodic_qh_ptr =
+01375                             hcd->non_periodic_qh_ptr->next;
+01376                 }
+01377 
+01378         } while (hcd->non_periodic_qh_ptr != orig_qh_ptr);
+01379 
+01380         if (!hcd->core_if->dma_enable) {
+01381                 gintmsk_data_t intr_mask = {.d32 = 0 };
+01382                 intr_mask.b.nptxfempty = 1;
+01383 
+01384 #ifdef DEBUG
+01385                 tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts);
+01386                 DWC_DEBUGPL(DBG_HCDV,
+01387                             "  NP Tx Req Queue Space Avail (after queue): %d\n",
+01388                             tx_status.b.nptxqspcavail);
+01389                 DWC_DEBUGPL(DBG_HCDV,
+01390                             "  NP Tx FIFO Space Avail (after queue): %d\n",
+01391                             tx_status.b.nptxfspcavail);
+01392 #endif
+01393                 if (more_to_do || no_queue_space || no_fifo_space) {
+01394                         /*
+01395                          * May need to queue more transactions as the request
+01396                          * queue or Tx FIFO empties. Enable the non-periodic
+01397                          * Tx FIFO empty interrupt. (Always use the half-empty
+01398                          * level to ensure that new requests are loaded as
+01399                          * soon as possible.)
+01400                          */
+01401                         dwc_modify_reg32(&global_regs->gintmsk, 0,
+01402                                          intr_mask.d32);
+01403                 } else {
+01404                         /*
+01405                          * Disable the Tx FIFO empty interrupt since there are
+01406                          * no more transactions that need to be queued right
+01407                          * now. This function is called from interrupt
+01408                          * handlers to queue more transactions as transfer
+01409                          * states change.
+01410                          */
+01411                         dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32,
+01412                                          0);
+01413                 }
+01414         }
+01415 }
+01416 
+01426 void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
+01427                                            dwc_otg_transaction_type_e tr_type)
+01428 {
+01429 #ifdef DEBUG_SOF
+01430         DWC_DEBUGPL(DBG_HCD, "Queue Transactions\n");
+01431 #endif
+01432         /* Process host channels associated with periodic transfers. */
+01433         if ((tr_type == DWC_OTG_TRANSACTION_PERIODIC ||
+01434              tr_type == DWC_OTG_TRANSACTION_ALL) &&
+01435             !DWC_LIST_EMPTY(&hcd->periodic_sched_assigned)) {
+01436 
+01437                 process_periodic_channels(hcd);
+01438         }
+01439 
+01440         /* Process host channels associated with non-periodic transfers. */
+01441         if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC ||
+01442             tr_type == DWC_OTG_TRANSACTION_ALL) {
+01443                 if (!DWC_LIST_EMPTY(&hcd->non_periodic_sched_active)) {
+01444                         process_non_periodic_channels(hcd);
+01445                 } else {
+01446                         /*
+01447                          * Ensure NP Tx FIFO empty interrupt is disabled when
+01448                          * there are no non-periodic transfers to process.
+01449                          */
+01450                         gintmsk_data_t gintmsk = {.d32 = 0 };
+01451                         gintmsk.b.nptxfempty = 1;
+01452                         dwc_modify_reg32(&hcd->core_if->core_global_regs->
+01453                                          gintmsk, gintmsk.d32, 0);
+01454                 }
+01455         }
+01456 }
+01457  
+01458 #ifdef DWC_HS_ELECT_TST
+01459 /*
+01460  * Quick and dirty hack to implement the HS Electrical Test
+01461  * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature.
+01462  *
+01463  * This code was copied from our userspace app "hset". It sends a
+01464  * Get Device Descriptor control sequence in two parts, first the
+01465  * Setup packet by itself, followed some time later by the In and
+01466  * Ack packets. Rather than trying to figure out how to add this
+01467  * functionality to the normal driver code, we just hijack the
+01468  * hardware, using these two function to drive the hardware
+01469  * directly.
+01470  */
+01471 
+01472 static dwc_otg_core_global_regs_t *global_regs;
+01473 static dwc_otg_host_global_regs_t *hc_global_regs;
+01474 static dwc_otg_hc_regs_t *hc_regs;
+01475 static uint32_t *data_fifo;
+01476 
+01477 static void do_setup(void)
+01478 {
+01479         gintsts_data_t gintsts;
+01480         hctsiz_data_t hctsiz;
+01481         hcchar_data_t hcchar;
+01482         haint_data_t haint;
+01483         hcint_data_t hcint;
+01484 
+01485         /* Enable HAINTs */
+01486         dwc_write_reg32(&hc_global_regs->haintmsk, 0x0001);
+01487 
+01488         /* Enable HCINTs */
+01489         dwc_write_reg32(&hc_regs->hcintmsk, 0x04a3);
+01490 
+01491         /* Read GINTSTS */
+01492         gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01493 
+01494         /* Read HAINT */
+01495         haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
+01496 
+01497         /* Read HCINT */
+01498         hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+01499 
+01500         /* Read HCCHAR */
+01501         hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01502 
+01503         /* Clear HCINT */
+01504         dwc_write_reg32(&hc_regs->hcint, hcint.d32);
+01505 
+01506         /* Clear HAINT */
+01507         dwc_write_reg32(&hc_global_regs->haint, haint.d32);
+01508 
+01509         /* Clear GINTSTS */
+01510         dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+01511 
+01512         /* Read GINTSTS */
+01513         gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01514 
+01515         /*
+01516          * Send Setup packet (Get Device Descriptor)
+01517          */
+01518 
+01519         /* Make sure channel is disabled */
+01520         hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01521         if (hcchar.b.chen) {
+01522                 hcchar.b.chdis = 1;
+01523 //              hcchar.b.chen = 1;
+01524                 dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+01525                 //sleep(1);
+01526                 dwc_mdelay(1000);
+01527 
+01528                 /* Read GINTSTS */
+01529                 gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01530 
+01531                 /* Read HAINT */
+01532                 haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
+01533 
+01534                 /* Read HCINT */
+01535                 hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+01536 
+01537                 /* Read HCCHAR */
+01538                 hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01539 
+01540                 /* Clear HCINT */
+01541                 dwc_write_reg32(&hc_regs->hcint, hcint.d32);
+01542 
+01543                 /* Clear HAINT */
+01544                 dwc_write_reg32(&hc_global_regs->haint, haint.d32);
+01545 
+01546                 /* Clear GINTSTS */
+01547                 dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+01548 
+01549                 hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01550         }
+01551 
+01552         /* Set HCTSIZ */
+01553         hctsiz.d32 = 0;
+01554         hctsiz.b.xfersize = 8;
+01555         hctsiz.b.pktcnt = 1;
+01556         hctsiz.b.pid = DWC_OTG_HC_PID_SETUP;
+01557         dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
+01558 
+01559         /* Set HCCHAR */
+01560         hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01561         hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
+01562         hcchar.b.epdir = 0;
+01563         hcchar.b.epnum = 0;
+01564         hcchar.b.mps = 8;
+01565         hcchar.b.chen = 1;
+01566         dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+01567 
+01568         /* Fill FIFO with Setup data for Get Device Descriptor */
+01569         data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
+01570         dwc_write_reg32(data_fifo++, 0x01000680);
+01571         dwc_write_reg32(data_fifo++, 0x00080000);
+01572 
+01573         gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01574 
+01575         /* Wait for host channel interrupt */
+01576         do {
+01577                 gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01578         } while (gintsts.b.hcintr == 0);
+01579 
+01580 
+01581         /* Disable HCINTs */
+01582         dwc_write_reg32(&hc_regs->hcintmsk, 0x0000);
+01583 
+01584         /* Disable HAINTs */
+01585         dwc_write_reg32(&hc_global_regs->haintmsk, 0x0000);
+01586 
+01587         /* Read HAINT */
+01588         haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
+01589 
+01590         /* Read HCINT */
+01591         hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+01592 
+01593         /* Read HCCHAR */
+01594         hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01595 
+01596         /* Clear HCINT */
+01597         dwc_write_reg32(&hc_regs->hcint, hcint.d32);
+01598 
+01599         /* Clear HAINT */
+01600         dwc_write_reg32(&hc_global_regs->haint, haint.d32);
+01601 
+01602         /* Clear GINTSTS */
+01603         dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+01604 
+01605         /* Read GINTSTS */
+01606         gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01607 }
+01608 
+01609 static void do_in_ack(void)
+01610 {
+01611         gintsts_data_t gintsts;
+01612         hctsiz_data_t hctsiz;
+01613         hcchar_data_t hcchar;
+01614         haint_data_t haint;
+01615         hcint_data_t hcint;
+01616         host_grxsts_data_t grxsts;
+01617 
+01618         /* Enable HAINTs */
+01619         dwc_write_reg32(&hc_global_regs->haintmsk, 0x0001);
+01620 
+01621         /* Enable HCINTs */
+01622         dwc_write_reg32(&hc_regs->hcintmsk, 0x04a3);
+01623 
+01624         /* Read GINTSTS */
+01625         gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01626 
+01627         /* Read HAINT */
+01628         haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
+01629 
+01630         /* Read HCINT */
+01631         hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+01632 
+01633         /* Read HCCHAR */
+01634         hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01635 
+01636         /* Clear HCINT */
+01637         dwc_write_reg32(&hc_regs->hcint, hcint.d32);
+01638 
+01639         /* Clear HAINT */
+01640         dwc_write_reg32(&hc_global_regs->haint, haint.d32);
+01641 
+01642         /* Clear GINTSTS */
+01643         dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+01644 
+01645         /* Read GINTSTS */
+01646         gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01647 
+01648         /*
+01649          * Receive Control In packet
+01650          */
+01651 
+01652         /* Make sure channel is disabled */
+01653         hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01654         if (hcchar.b.chen) {
+01655                 hcchar.b.chdis = 1;
+01656                 hcchar.b.chen = 1;
+01657                 dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+01658                 //sleep(1);
+01659                 dwc_mdelay(1000);
+01660 
+01661                 /* Read GINTSTS */
+01662                 gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01663 
+01664                 /* Read HAINT */
+01665                 haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
+01666 
+01667                 /* Read HCINT */
+01668                 hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+01669 
+01670                 /* Read HCCHAR */
+01671                 hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01672 
+01673                 /* Clear HCINT */
+01674                 dwc_write_reg32(&hc_regs->hcint, hcint.d32);
+01675 
+01676                 /* Clear HAINT */
+01677                 dwc_write_reg32(&hc_global_regs->haint, haint.d32);
+01678 
+01679                 /* Clear GINTSTS */
+01680                 dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+01681 
+01682                 hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01683         }
+01684 
+01685         /* Set HCTSIZ */
+01686         hctsiz.d32 = 0;
+01687         hctsiz.b.xfersize = 8;
+01688         hctsiz.b.pktcnt = 1;
+01689         hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
+01690         dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
+01691 
+01692         /* Set HCCHAR */
+01693         hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01694         hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
+01695         hcchar.b.epdir = 1;
+01696         hcchar.b.epnum = 0;
+01697         hcchar.b.mps = 8;
+01698         hcchar.b.chen = 1;
+01699         dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+01700 
+01701         gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01702 
+01703         /* Wait for receive status queue interrupt */
+01704         do {
+01705                 gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01706         } while (gintsts.b.rxstsqlvl == 0);
+01707 
+01708 
+01709         /* Read RXSTS */
+01710         grxsts.d32 = dwc_read_reg32(&global_regs->grxstsp);
+01711 
+01712         /* Clear RXSTSQLVL in GINTSTS */
+01713         gintsts.d32 = 0;
+01714         gintsts.b.rxstsqlvl = 1;
+01715         dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+01716 
+01717         switch (grxsts.b.pktsts) {
+01718         case DWC_GRXSTS_PKTSTS_IN:
+01719                 /* Read the data into the host buffer */
+01720                 if (grxsts.b.bcnt > 0) {
+01721                         int i;
+01722                         int word_count = (grxsts.b.bcnt + 3) / 4;
+01723 
+01724                         data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
+01725 
+01726                         for (i = 0; i < word_count; i++) {
+01727                                 (void)dwc_read_reg32(data_fifo++);
+01728                         }
+01729                 }
+01730                 break;
+01731 
+01732         default:
+01733                 break;
+01734         }
+01735 
+01736         gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01737 
+01738         /* Wait for receive status queue interrupt */
+01739         do {
+01740                 gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01741         } while (gintsts.b.rxstsqlvl == 0);
+01742 
+01743 
+01744         /* Read RXSTS */
+01745         grxsts.d32 = dwc_read_reg32(&global_regs->grxstsp);
+01746 
+01747         /* Clear RXSTSQLVL in GINTSTS */
+01748         gintsts.d32 = 0;
+01749         gintsts.b.rxstsqlvl = 1;
+01750         dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+01751 
+01752         switch (grxsts.b.pktsts) {
+01753         case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
+01754                 break;
+01755 
+01756         default:
+01757                 break;
+01758         }
+01759 
+01760         gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01761 
+01762         /* Wait for host channel interrupt */
+01763         do {
+01764                 gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01765         } while (gintsts.b.hcintr == 0);
+01766 
+01767 
+01768         /* Read HAINT */
+01769         haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
+01770 
+01771         /* Read HCINT */
+01772         hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+01773 
+01774         /* Read HCCHAR */
+01775         hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01776 
+01777         /* Clear HCINT */
+01778         dwc_write_reg32(&hc_regs->hcint, hcint.d32);
+01779 
+01780         /* Clear HAINT */
+01781         dwc_write_reg32(&hc_global_regs->haint, haint.d32);
+01782 
+01783         /* Clear GINTSTS */
+01784         dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+01785 
+01786         /* Read GINTSTS */
+01787         gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01788 
+01789 //      usleep(100000);
+01790 //      mdelay(100);
+01791         dwc_mdelay(1);
+01792 
+01793         /*
+01794          * Send handshake packet
+01795          */
+01796 
+01797         /* Read HAINT */
+01798         haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
+01799 
+01800         /* Read HCINT */
+01801         hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+01802 
+01803         /* Read HCCHAR */
+01804         hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01805 
+01806         /* Clear HCINT */
+01807         dwc_write_reg32(&hc_regs->hcint, hcint.d32);
+01808 
+01809         /* Clear HAINT */
+01810         dwc_write_reg32(&hc_global_regs->haint, haint.d32);
+01811 
+01812         /* Clear GINTSTS */
+01813         dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+01814 
+01815         /* Read GINTSTS */
+01816         gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01817 
+01818         /* Make sure channel is disabled */
+01819         hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01820         if (hcchar.b.chen) {
+01821                 hcchar.b.chdis = 1;
+01822                 hcchar.b.chen = 1;
+01823                 dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+01824                 //sleep(1);
+01825                 dwc_mdelay(1000);
+01826 
+01827                 /* Read GINTSTS */
+01828                 gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01829 
+01830                 /* Read HAINT */
+01831                 haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
+01832 
+01833                 /* Read HCINT */
+01834                 hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+01835 
+01836                 /* Read HCCHAR */
+01837                 hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01838 
+01839                 /* Clear HCINT */
+01840                 dwc_write_reg32(&hc_regs->hcint, hcint.d32);
+01841 
+01842                 /* Clear HAINT */
+01843                 dwc_write_reg32(&hc_global_regs->haint, haint.d32);
+01844 
+01845                 /* Clear GINTSTS */
+01846                 dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+01847 
+01848                 hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01849         }
+01850 
+01851         /* Set HCTSIZ */
+01852         hctsiz.d32 = 0;
+01853         hctsiz.b.xfersize = 0;
+01854         hctsiz.b.pktcnt = 1;
+01855         hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
+01856         dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
+01857 
+01858         /* Set HCCHAR */
+01859         hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01860         hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
+01861         hcchar.b.epdir = 0;
+01862         hcchar.b.epnum = 0;
+01863         hcchar.b.mps = 8;
+01864         hcchar.b.chen = 1;
+01865         dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+01866 
+01867         gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01868 
+01869         /* Wait for host channel interrupt */
+01870         do {
+01871                 gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01872         } while (gintsts.b.hcintr == 0);
+01873 
+01874 
+01875         /* Disable HCINTs */
+01876         dwc_write_reg32(&hc_regs->hcintmsk, 0x0000);
+01877 
+01878         /* Disable HAINTs */
+01879         dwc_write_reg32(&hc_global_regs->haintmsk, 0x0000);
+01880 
+01881         /* Read HAINT */
+01882         haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
+01883 
+01884         /* Read HCINT */
+01885         hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+01886 
+01887         /* Read HCCHAR */
+01888         hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01889 
+01890         /* Clear HCINT */
+01891         dwc_write_reg32(&hc_regs->hcint, hcint.d32);
+01892 
+01893         /* Clear HAINT */
+01894         dwc_write_reg32(&hc_global_regs->haint, haint.d32);
+01895 
+01896         /* Clear GINTSTS */
+01897         dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+01898 
+01899         /* Read GINTSTS */
+01900         gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+01901 }
+01902 #endif
+01903 
+01905 int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
+01906                             uint16_t typeReq,
+01907                             uint16_t wValue,
+01908                             uint16_t wIndex, uint8_t * buf, uint16_t wLength)
+01909 {
+01910         int retval = 0;
+01911 
+01912         dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
+01913         usb_hub_descriptor_t *hub_desc;
+01914         hprt0_data_t hprt0 = {.d32 = 0 };
+01915 
+01916         uint32_t port_status;
+01917 
+01918         switch (typeReq) {
+01919         case UCR_CLEAR_HUB_FEATURE:
+01920                 DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+01921                             "ClearHubFeature 0x%x\n", wValue);
+01922                 switch (wValue) {
+01923                 case UHF_C_HUB_LOCAL_POWER:
+01924                 case UHF_C_HUB_OVER_CURRENT:
+01925                         /* Nothing required here */
+01926                         break;
+01927                 default:
+01928                         retval = -DWC_E_INVALID;
+01929                         DWC_ERROR("DWC OTG HCD - "
+01930                                   "ClearHubFeature request %xh unknown\n",
+01931                                   wValue);
+01932                 }
+01933                 break;
+01934         case UCR_CLEAR_PORT_FEATURE:
+01935 #ifdef CONFIG_USB_DWC_OTG_LPM
+01936                 if (wValue != UHF_PORT_L1)
+01937 #endif
+01938                         if (!wIndex || wIndex > 1)
+01939                                 goto error;
+01940 
+01941                 switch (wValue) {
+01942                 case UHF_PORT_ENABLE:
+01943                         DWC_DEBUGPL(DBG_ANY, "DWC OTG HCD HUB CONTROL - "
+01944                                     "ClearPortFeature USB_PORT_FEAT_ENABLE\n");
+01945                         hprt0.d32 = dwc_otg_read_hprt0(core_if);
+01946                         hprt0.b.prtena = 1;
+01947                         dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+01948                         break;
+01949                 case UHF_PORT_SUSPEND:
+01950                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+01951                                     "ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
+01952 
+01953                         dwc_write_reg32(core_if->pcgcctl, 0);
+01954                         dwc_mdelay(5);
+01955 
+01956                         hprt0.d32 = dwc_otg_read_hprt0(core_if);
+01957                         hprt0.b.prtres = 1;
+01958                         dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+01959                         hprt0.b.prtsusp = 0;
+01960                         /* Clear Resume bit */
+01961                         dwc_mdelay(100);
+01962                         hprt0.b.prtres = 0;
+01963                         dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+01964                         break;
+01965 #ifdef CONFIG_USB_DWC_OTG_LPM
+01966                 case UHF_PORT_L1:
+01967                         {
+01968                                 pcgcctl_data_t pcgcctl = {.d32 = 0 };
+01969                                 glpmcfg_data_t lpmcfg = {.d32 = 0 };
+01970 
+01971                                 lpmcfg.d32 =
+01972                                     dwc_read_reg32(&core_if->core_global_regs->
+01973                                                    glpmcfg);
+01974                                 lpmcfg.b.en_utmi_sleep = 0;
+01975                                 lpmcfg.b.hird_thres &= (~(1 << 4));
+01976                                 lpmcfg.b.prt_sleep_sts = 1;
+01977                                 dwc_write_reg32(&core_if->core_global_regs->
+01978                                                 glpmcfg, lpmcfg.d32);
+01979 
+01980                                 /* Clear Enbl_L1Gating bit. */
+01981                                 pcgcctl.b.enbl_sleep_gating = 1;
+01982                                 dwc_modify_reg32(core_if->pcgcctl, pcgcctl.d32,
+01983                                                  0);
+01984 
+01985                                 dwc_mdelay(5);
+01986 
+01987                                 hprt0.d32 = dwc_otg_read_hprt0(core_if);
+01988                                 hprt0.b.prtres = 1;
+01989                                 dwc_write_reg32(core_if->host_if->hprt0,
+01990                                                 hprt0.d32);
+01991                                 /* This bit will be cleared in wakeup interrupt handle */
+01992                                 break;
+01993                         }
+01994 #endif
+01995                 case UHF_PORT_POWER:
+01996                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+01997                                     "ClearPortFeature USB_PORT_FEAT_POWER\n");
+01998                         hprt0.d32 = dwc_otg_read_hprt0(core_if);
+01999                         hprt0.b.prtpwr = 0;
+02000                         dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+02001                         break;
+02002                 case UHF_PORT_INDICATOR:
+02003                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+02004                                     "ClearPortFeature USB_PORT_FEAT_INDICATOR\n");
+02005                         /* Port inidicator not supported */
+02006                         break;
+02007                 case UHF_C_PORT_CONNECTION:
+02008                         /* Clears drivers internal connect status change
+02009                          * flag */
+02010                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+02011                                     "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n");
+02012                         dwc_otg_hcd->flags.b.port_connect_status_change = 0;
+02013                         break;
+02014                 case UHF_C_PORT_RESET:
+02015                         /* Clears the driver's internal Port Reset Change
+02016                          * flag */
+02017                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+02018                                     "ClearPortFeature USB_PORT_FEAT_C_RESET\n");
+02019                         dwc_otg_hcd->flags.b.port_reset_change = 0;
+02020                         break;
+02021                 case UHF_C_PORT_ENABLE:
+02022                         /* Clears the driver's internal Port
+02023                          * Enable/Disable Change flag */
+02024                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+02025                                     "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n");
+02026                         dwc_otg_hcd->flags.b.port_enable_change = 0;
+02027                         break;
+02028                 case UHF_C_PORT_SUSPEND:
+02029                         /* Clears the driver's internal Port Suspend
+02030                          * Change flag, which is set when resume signaling on
+02031                          * the host port is complete */
+02032                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+02033                                     "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n");
+02034                         dwc_otg_hcd->flags.b.port_suspend_change = 0;
+02035                         break;
+02036 #ifdef CONFIG_USB_DWC_OTG_LPM
+02037                 case UHF_C_PORT_L1:
+02038                         dwc_otg_hcd->flags.b.port_l1_change = 0;
+02039                         break;
+02040 #endif
+02041                 case UHF_C_PORT_OVER_CURRENT:
+02042                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+02043                                     "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n");
+02044                         dwc_otg_hcd->flags.b.port_over_current_change = 0;
+02045                         break;
+02046                 default:
+02047                         retval = -DWC_E_INVALID;
+02048                         DWC_ERROR("DWC OTG HCD - "
+02049                                   "ClearPortFeature request %xh "
+02050                                   "unknown or unsupported\n", wValue);
+02051                 }
+02052                 break;
+02053         case UCR_GET_HUB_DESCRIPTOR:
+02054                 DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+02055                             "GetHubDescriptor\n");
+02056                 hub_desc = (usb_hub_descriptor_t *) buf;
+02057                 hub_desc->bDescLength = 9;
+02058                 hub_desc->bDescriptorType = 0x29;
+02059                 hub_desc->bNbrPorts = 1;
+02060                 USETW(hub_desc->wHubCharacteristics, 0x08);
+02061                 hub_desc->bPwrOn2PwrGood = 1;
+02062                 hub_desc->bHubContrCurrent = 0;
+02063                 hub_desc->DeviceRemovable[0] = 0;
+02064                 hub_desc->DeviceRemovable[1] = 0xff;
+02065                 break;
+02066         case UCR_GET_HUB_STATUS:
+02067                 DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+02068                             "GetHubStatus\n");
+02069                 DWC_MEMSET(buf, 0, 4);
+02070                 break;
+02071         case UCR_GET_PORT_STATUS:
+02072                 DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+02073                             "GetPortStatus\n");
+02074                 if (!wIndex || wIndex > 1)
+02075                         goto error;
+02076 
+02077                 port_status = 0;
+02078 
+02079                 if (dwc_otg_hcd->flags.b.port_connect_status_change)
+02080                         port_status |= (1 << UHF_C_PORT_CONNECTION);
+02081 
+02082                 if (dwc_otg_hcd->flags.b.port_enable_change)
+02083                         port_status |= (1 << UHF_C_PORT_ENABLE);
+02084 
+02085                 if (dwc_otg_hcd->flags.b.port_suspend_change)
+02086                         port_status |= (1 << UHF_C_PORT_SUSPEND);
+02087 
+02088                 if (dwc_otg_hcd->flags.b.port_l1_change)
+02089                         port_status |= (1 << UHF_C_PORT_L1);
+02090 
+02091                 if (dwc_otg_hcd->flags.b.port_reset_change) {
+02092                         port_status |= (1 << UHF_C_PORT_RESET);
+02093                 }
+02094 
+02095                 if (dwc_otg_hcd->flags.b.port_over_current_change) {
+02096                         DWC_ERROR("Device Not Supported\n");
+02097                         port_status |= (1 << UHF_C_PORT_OVER_CURRENT);
+02098                 }
+02099 
+02100                 if (!dwc_otg_hcd->flags.b.port_connect_status) {
+02101                         /*
+02102                          * The port is disconnected, which means the core is
+02103                          * either in device mode or it soon will be. Just
+02104                          * return 0's for the remainder of the port status
+02105                          * since the port register can't be read if the core
+02106                          * is in device mode.
+02107                          */
+02108                         *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
+02109                         break;
+02110                 }
+02111 
+02112                 hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
+02113                 DWC_DEBUGPL(DBG_HCDV, "  HPRT0: 0x%08x\n", hprt0.d32);
+02114 
+02115                 if (hprt0.b.prtconnsts)
+02116                         port_status |= (1 << UHF_PORT_CONNECTION);
+02117 
+02118                 if (hprt0.b.prtena)
+02119                         port_status |= (1 << UHF_PORT_ENABLE);
+02120 
+02121                 if (hprt0.b.prtsusp)
+02122                         port_status |= (1 << UHF_PORT_SUSPEND);
+02123 
+02124                 if (hprt0.b.prtovrcurract)
+02125                         port_status |= (1 << UHF_PORT_OVER_CURRENT);
+02126 
+02127                 if (hprt0.b.prtrst)
+02128                         port_status |= (1 << UHF_PORT_RESET);
+02129 
+02130                 if (hprt0.b.prtpwr)
+02131                         port_status |= (1 << UHF_PORT_POWER);
+02132 
+02133                 if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED)
+02134                         port_status |= (1 << UHF_PORT_HIGH_SPEED);
+02135                 else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED)
+02136                         port_status |= (1 << UHF_PORT_LOW_SPEED);
+02137 
+02138                 if (hprt0.b.prttstctl)
+02139                         port_status |= (1 << UHF_PORT_TEST);
+02140                 if (dwc_otg_get_lpm_portsleepstatus(dwc_otg_hcd->core_if)) {
+02141                         port_status |= (1 << UHF_PORT_L1);
+02142                 }
+02143 
+02144                 /* USB_PORT_FEAT_INDICATOR unsupported always 0 */
+02145 
+02146                 *((__le32 *) buf) = dwc_cpu_to_le32(&port_status);
+02147 
+02148                 break;
+02149         case UCR_SET_HUB_FEATURE:
+02150                 DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+02151                             "SetHubFeature\n");
+02152                 /* No HUB features supported */
+02153                 break;
+02154         case UCR_SET_PORT_FEATURE:
+02155                 if (wValue != UHF_PORT_TEST && (!wIndex || wIndex > 1))
+02156                         goto error;
+02157 
+02158                 if (!dwc_otg_hcd->flags.b.port_connect_status) {
+02159                         /*
+02160                          * The port is disconnected, which means the core is
+02161                          * either in device mode or it soon will be. Just
+02162                          * return without doing anything since the port
+02163                          * register can't be written if the core is in device
+02164                          * mode.
+02165                          */
+02166                         break;
+02167                 }
+02168 
+02169                 switch (wValue) {
+02170                 case UHF_PORT_SUSPEND:
+02171                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+02172                                     "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
+02173                         if (dwc_otg_hcd_otg_port(dwc_otg_hcd) == wIndex &&
+02174                             dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
+02175                                 gotgctl_data_t gotgctl = {.d32 = 0 };
+02176                                 gotgctl.b.hstsethnpen = 1;
+02177                                 dwc_modify_reg32(&core_if->core_global_regs->
+02178                                                  gotgctl, 0, gotgctl.d32);
+02179                                 core_if->op_state = A_SUSPEND;
+02180                         }
+02181                         hprt0.d32 = dwc_otg_read_hprt0(core_if);
+02182                         hprt0.b.prtsusp = 1;
+02183                         dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+02184                         {
+02185                                 uint64_t flags;
+02186                                 /* Update lx_state */
+02187                                 DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
+02188                                 core_if->lx_state = DWC_OTG_L2;
+02189                                 DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
+02190                         }
+02191                         /* Suspend the Phy Clock */
+02192                         {
+02193                                 pcgcctl_data_t pcgcctl = {.d32 = 0 };
+02194                                 pcgcctl.b.stoppclk = 1;
+02195                                 dwc_modify_reg32(core_if->pcgcctl, 0,
+02196                                                  pcgcctl.d32);
+02197                         }
+02198 
+02199                         /* For HNP the bus must be suspended for at least 200ms. */
+02200                         if (dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) {
+02201                                 dwc_mdelay(200);
+02202                         }
+02203                         break;
+02204                 case UHF_PORT_POWER:
+02205                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+02206                                     "SetPortFeature - USB_PORT_FEAT_POWER\n");
+02207                         hprt0.d32 = dwc_otg_read_hprt0(core_if);
+02208                         hprt0.b.prtpwr = 1;
+02209                         dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+02210                         break;
+02211                 case UHF_PORT_RESET:
+02212                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+02213                                     "SetPortFeature - USB_PORT_FEAT_RESET\n");
+02214                         {
+02215                                 pcgcctl_data_t pcgcctl = {.d32 = 0 };
+02216                                 pcgcctl.b.enbl_sleep_gating = 1;
+02217                                 pcgcctl.b.stoppclk = 1;
+02218                                 dwc_modify_reg32(core_if->pcgcctl, pcgcctl.d32,
+02219                                                  0);
+02220                                 dwc_write_reg32(core_if->pcgcctl, 0);
+02221                         }
+02222 #ifdef CONFIG_USB_DWC_OTG_LPM
+02223                         {
+02224                                 glpmcfg_data_t lpmcfg;
+02225                                 lpmcfg.d32 =
+02226                                     dwc_read_reg32(&core_if->core_global_regs->
+02227                                                    glpmcfg);
+02228                                 if (lpmcfg.b.prt_sleep_sts) {
+02229                                         lpmcfg.b.en_utmi_sleep = 0;
+02230                                         lpmcfg.b.hird_thres &= (~(1 << 4));
+02231                                         dwc_write_reg32(&core_if->
+02232                                                         core_global_regs->
+02233                                                         glpmcfg, lpmcfg.d32);
+02234                                         dwc_mdelay(1);
+02235                                 }
+02236                         }
+02237 #endif
+02238                         hprt0.d32 = dwc_otg_read_hprt0(core_if);
+02239                         /* When B-Host the Port reset bit is set in
+02240                          * the Start HCD Callback function, so that
+02241                          * the reset is started within 1ms of the HNP
+02242                          * success interrupt. */
+02243                         if (!dwc_otg_hcd_is_b_host(dwc_otg_hcd)) {
+02244                                 hprt0.b.prtrst = 1;
+02245                                 dwc_write_reg32(core_if->host_if->hprt0,
+02246                                                 hprt0.d32);
+02247                         }
+02248                         /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
+02249                         dwc_mdelay(60);
+02250                         hprt0.b.prtrst = 0;
+02251                         dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+02252                         core_if->lx_state = DWC_OTG_L0; /* Now back to the on state */
+02253                         break;
+02254 #ifdef DWC_HS_ELECT_TST
+02255                 case UHF_PORT_TEST:
+02256                         {
+02257                                 uint32_t t;
+02258                                 gintmsk_data_t gintmsk;
+02259 
+02260                                 t = (wIndex >> 8);      /* MSB wIndex USB */
+02261                                 DWC_DEBUGPL(DBG_HCD,
+02262                                             "DWC OTG HCD HUB CONTROL - "
+02263                                             "SetPortFeature - USB_PORT_FEAT_TEST %d\n",
+02264                                             t);
+02265                                 DWC_WARN("USB_PORT_FEAT_TEST %d\n", t);
+02266                                 if (t < 6) {
+02267                                         hprt0.d32 = dwc_otg_read_hprt0(core_if);
+02268                                         hprt0.b.prttstctl = t;
+02269                                         dwc_write_reg32(core_if->host_if->hprt0,
+02270                                                         hprt0.d32);
+02271                                 } else {
+02272                                         /* Setup global vars with reg addresses (quick and
+02273                                          * dirty hack, should be cleaned up)
+02274                                          */
+02275                                         global_regs = core_if->core_global_regs;
+02276                                         hc_global_regs =
+02277                                             core_if->host_if->host_global_regs;
+02278                                         hc_regs =
+02279                                             (dwc_otg_hc_regs_t *) ((char *)
+02280                                                                    global_regs +
+02281                                                                    0x500);
+02282                                         data_fifo =
+02283                                             (uint32_t *) ((char *)global_regs +
+02284                                                           0x1000);
+02285 
+02286                                         if (t == 6) {   /* HS_HOST_PORT_SUSPEND_RESUME */
+02287                                                 /* Save current interrupt mask */
+02288                                                 gintmsk.d32 =
+02289                                                     dwc_read_reg32
+02290                                                     (&global_regs->gintmsk);
+02291 
+02292                                                 /* Disable all interrupts while we muck with
+02293                                                  * the hardware directly
+02294                                                  */
+02295                                                 dwc_write_reg32(&global_regs->
+02296                                                                 gintmsk, 0);
+02297 
+02298                                                 /* 15 second delay per the test spec */
+02299                                                 dwc_mdelay(15000);
+02300 
+02301                                                 /* Drive suspend on the root port */
+02302                                                 hprt0.d32 =
+02303                                                     dwc_otg_read_hprt0(core_if);
+02304                                                 hprt0.b.prtsusp = 1;
+02305                                                 hprt0.b.prtres = 0;
+02306                                                 dwc_write_reg32(core_if->
+02307                                                                 host_if->hprt0,
+02308                                                                 hprt0.d32);
+02309 
+02310                                                 /* 15 second delay per the test spec */
+02311                                                 dwc_mdelay(15000);
+02312 
+02313                                                 /* Drive resume on the root port */
+02314                                                 hprt0.d32 =
+02315                                                     dwc_otg_read_hprt0(core_if);
+02316                                                 hprt0.b.prtsusp = 0;
+02317                                                 hprt0.b.prtres = 1;
+02318                                                 dwc_write_reg32(core_if->
+02319                                                                 host_if->hprt0,
+02320                                                                 hprt0.d32);
+02321                                                 dwc_mdelay(100);
+02322 
+02323                                                 /* Clear the resume bit */
+02324                                                 hprt0.b.prtres = 0;
+02325                                                 dwc_write_reg32(core_if->
+02326                                                                 host_if->hprt0,
+02327                                                                 hprt0.d32);
+02328 
+02329                                                 /* Restore interrupts */
+02330                                                 dwc_write_reg32(&global_regs->
+02331                                                                 gintmsk,
+02332                                                                 gintmsk.d32);
+02333                                         } else if (t == 7) {    /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
+02334                                                 /* Save current interrupt mask */
+02335                                                 gintmsk.d32 =
+02336                                                     dwc_read_reg32
+02337                                                     (&global_regs->gintmsk);
+02338 
+02339                                                 /* Disable all interrupts while we muck with
+02340                                                  * the hardware directly
+02341                                                  */
+02342                                                 dwc_write_reg32(&global_regs->
+02343                                                                 gintmsk, 0);
+02344 
+02345                                                 /* 15 second delay per the test spec */
+02346                                                 dwc_mdelay(15000);
+02347 
+02348                                                 /* Send the Setup packet */
+02349                                                 do_setup();
+02350 
+02351                                                 /* 15 second delay so nothing else happens for awhile */
+02352                                                 dwc_mdelay(15000);
+02353 
+02354                                                 /* Restore interrupts */
+02355                                                 dwc_write_reg32(&global_regs->
+02356                                                                 gintmsk,
+02357                                                                 gintmsk.d32);
+02358                                         } else if (t == 8) {    /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
+02359                                                 /* Save current interrupt mask */
+02360                                                 gintmsk.d32 =
+02361                                                     dwc_read_reg32
+02362                                                     (&global_regs->gintmsk);
+02363 
+02364                                                 /* Disable all interrupts while we muck with
+02365                                                  * the hardware directly
+02366                                                  */
+02367                                                 dwc_write_reg32(&global_regs->
+02368                                                                 gintmsk, 0);
+02369 
+02370                                                 /* Send the Setup packet */
+02371                                                 do_setup();
+02372 
+02373                                                 /* 15 second delay so nothing else happens for awhile */
+02374                                                 dwc_mdelay(15000);
+02375 
+02376                                                 /* Send the In and Ack packets */
+02377                                                 do_in_ack();
+02378 
+02379                                                 /* 15 second delay so nothing else happens for awhile */
+02380                                                 dwc_mdelay(15000);
+02381 
+02382                                                 /* Restore interrupts */
+02383                                                 dwc_write_reg32(&global_regs->
+02384                                                                 gintmsk,
+02385                                                                 gintmsk.d32);
+02386                                         }
+02387                                 }
+02388                                 break;
+02389                         }
+02390 #endif                          /* DWC_HS_ELECT_TST */
+02391 
+02392                 case UHF_PORT_INDICATOR:
+02393                         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+02394                                     "SetPortFeature - USB_PORT_FEAT_INDICATOR\n");
+02395                         /* Not supported */
+02396                         break;
+02397                 default:
+02398                         retval = -DWC_E_INVALID;
+02399                         DWC_ERROR("DWC OTG HCD - "
+02400                                   "SetPortFeature request %xh "
+02401                                   "unknown or unsupported\n", wValue);
+02402                         break;
+02403                 }
+02404                 break;
+02405 #ifdef CONFIG_USB_DWC_OTG_LPM
+02406         case UCR_SET_AND_TEST_PORT_FEATURE:
+02407                 if (wValue != UHF_PORT_L1) {
+02408                         goto error;
+02409                 }
+02410                 {
+02411                         int portnum, hird, devaddr, remwake;
+02412                         glpmcfg_data_t lpmcfg;
+02413                         uint32_t time_usecs;
+02414                         gintsts_data_t gintsts;
+02415                         gintmsk_data_t gintmsk;
+02416 
+02417                         if (!dwc_otg_get_param_lpm_enable(core_if)) {
+02418                                 goto error;
+02419                         }
+02420                         if (wValue != UHF_PORT_L1 || wLength != 1) {
+02421                                 goto error;
+02422                         }
+02423                         /* Check if the port currently is in SLEEP state */
+02424                         lpmcfg.d32 =
+02425                             dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
+02426                         if (lpmcfg.b.prt_sleep_sts) {
+02427                                 DWC_INFO("Port is already in sleep mode\n");
+02428                                 buf[0] = 0;     /* Return success */
+02429                                 break;
+02430                         }
+02431 
+02432                         portnum = wIndex & 0xf;
+02433                         hird = (wIndex >> 4) & 0xf;
+02434                         devaddr = (wIndex >> 8) & 0x7f;
+02435                         remwake = (wIndex >> 15);
+02436 
+02437                         if (portnum != 1) {
+02438                                 retval = -DWC_E_INVALID;
+02439                                 DWC_WARN
+02440                                     ("Wrong port number(%d) in SetandTestPortFeature request\n",
+02441                                      portnum);
+02442                                 break;
+02443                         }
+02444 
+02445                         DWC_PRINTF
+02446                             ("SetandTestPortFeature request: portnum = %d, hird = %d, devaddr = %d, rewake = %d\n",
+02447                              portnum, hird, devaddr, remwake);
+02448                         /* Disable LPM interrupt */
+02449                         gintmsk.d32 = 0;
+02450                         gintmsk.b.lpmtranrcvd = 1;
+02451                         dwc_modify_reg32(&core_if->core_global_regs->gintmsk,
+02452                                          gintmsk.d32, 0);
+02453 
+02454                         if (dwc_otg_hcd_send_lpm
+02455                             (dwc_otg_hcd, devaddr, hird, remwake)) {
+02456                                 retval = -DWC_E_INVALID;
+02457                                 break;
+02458                         }
+02459 
+02460                         time_usecs = 10 * (lpmcfg.b.retry_count + 1);
+02461                         /* We will consider timeout if time_usecs microseconds pass,
+02462                          * and we don't receive LPM transaction status.
+02463                          * After receiving non-error responce(ACK/NYET/STALL) from device,
+02464                          *  core will set lpmtranrcvd bit.
+02465                          */
+02466                         do {
+02467                                 gintsts.d32 =
+02468                                     dwc_read_reg32(&core_if->core_global_regs->
+02469                                                    gintsts);
+02470                                 if (gintsts.b.lpmtranrcvd) {
+02471                                         break;
+02472                                 }
+02473                                 dwc_udelay(1);
+02474                         } while (--time_usecs);
+02475                         /* lpm_int bit will be cleared in LPM interrupt handler */
+02476 
+02477                         /* Now fill status
+02478                          * 0x00 - Success
+02479                          * 0x10 - NYET
+02480                          * 0x11 - Timeout
+02481                          */
+02482                         if (!gintsts.b.lpmtranrcvd) {
+02483                                 buf[0] = 0x3;   /* Completion code is Timeout */
+02484                                 dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd);
+02485                         } else {
+02486                                 lpmcfg.d32 =
+02487                                     dwc_read_reg32(&core_if->core_global_regs->
+02488                                                    glpmcfg);
+02489                                 if (lpmcfg.b.lpm_resp == 0x3) {
+02490                                         /* ACK responce from the device */
+02491                                         buf[0] = 0x00;  /* Success */
+02492                                 } else if (lpmcfg.b.lpm_resp == 0x2) {
+02493                                         /* NYET responce from the device */
+02494                                         buf[0] = 0x2;
+02495                                 } else {
+02496                                         /* Otherwise responce with Timeout */
+02497                                         buf[0] = 0x3;
+02498                                 }
+02499                         }
+02500                         DWC_PRINTF("Device responce to LPM trans is %x\n",
+02501                                    lpmcfg.b.lpm_resp);
+02502                         dwc_modify_reg32(&core_if->core_global_regs->gintmsk, 0,
+02503                                          gintmsk.d32);
+02504 
+02505                         break;
+02506                 }
+02507 #endif                          /* CONFIG_USB_DWC_OTG_LPM */
+02508         default:
+02509               error:
+02510                 retval = -DWC_E_INVALID;
+02511                 DWC_WARN("DWC OTG HCD - "
+02512                          "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n",
+02513                          typeReq, wIndex, wValue);
+02514                 break;
+02515         }
+02516 
+02517         return retval;
+02518 }
+02519 
+02520 #ifdef CONFIG_USB_DWC_OTG_LPM
+02521 
+02522 int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd, uint8_t devaddr)
+02523 {
+02524         dwc_otg_core_if_t *core_if = hcd->core_if;
+02525         dwc_hc_t *hc;
+02526         hcchar_data_t hcchar;
+02527         gintmsk_data_t gintmsk = {.d32 = 0 };
+02528 
+02529         if (DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
+02530                 DWC_PRINTF("No free channel to select for LPM transaction\n");
+02531                 return -1;
+02532         }
+02533 
+02534         hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list);
+02535 
+02536         /* Mask host channel interrupts. */
+02537         gintmsk.b.hcintr = 1;
+02538         dwc_modify_reg32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
+02539 
+02540         /* Fill fields that core needs for LPM transaction */
+02541         hcchar.b.devaddr = devaddr;
+02542         hcchar.b.epnum = 0;
+02543         hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
+02544         hcchar.b.mps = 64;
+02545         hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
+02546         hcchar.b.epdir = 0;     /* OUT */
+02547         dwc_write_reg32(&core_if->host_if->hc_regs[hc->hc_num]->hcchar,
+02548                         hcchar.d32);
+02549 
+02550         /* Remove the host channel from the free list. */
+02551         DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry);
+02552 
+02553         DWC_PRINTF("hcnum = %d devaddr = %d\n", hc->hc_num, devaddr);
+02554 
+02555         return hc->hc_num;
+02556 }
+02557 
+02559 void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd)
+02560 {
+02561         dwc_hc_t *hc;
+02562         glpmcfg_data_t lpmcfg;
+02563         uint8_t hc_num;
+02564 
+02565         lpmcfg.d32 = dwc_read_reg32(&hcd->core_if->core_global_regs->glpmcfg);
+02566         hc_num = lpmcfg.b.lpm_chan_index;
+02567 
+02568         hc = hcd->hc_ptr_array[hc_num];
+02569 
+02570         DWC_PRINTF("Freeing channel %d after LPM\n", hc_num);
+02571         /* Return host channel to free list */
+02572         DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
+02573 }
+02574 
+02575 int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr, uint8_t hird,
+02576                          uint8_t bRemoteWake)
+02577 {
+02578         glpmcfg_data_t lpmcfg;
+02579         pcgcctl_data_t pcgcctl = {.d32 = 0 };
+02580         int channel;
+02581 
+02582         channel = dwc_otg_hcd_get_hc_for_lpm_tran(hcd, devaddr);
+02583         if (channel < 0) {
+02584                 return channel;
+02585         }
+02586 
+02587         pcgcctl.b.enbl_sleep_gating = 1;
+02588         dwc_modify_reg32(hcd->core_if->pcgcctl, 0, pcgcctl.d32);
+02589 
+02590         /* Read LPM config register */
+02591         lpmcfg.d32 = dwc_read_reg32(&hcd->core_if->core_global_regs->glpmcfg);
+02592 
+02593         /* Program LPM transaction fields */
+02594         lpmcfg.b.rem_wkup_en = bRemoteWake;
+02595         lpmcfg.b.hird = hird;
+02596         lpmcfg.b.hird_thres = 0x1c;
+02597         lpmcfg.b.lpm_chan_index = channel;
+02598         lpmcfg.b.en_utmi_sleep = 1;
+02599         /* Program LPM config register */
+02600         dwc_write_reg32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
+02601 
+02602         /* Send LPM transaction */
+02603         lpmcfg.b.send_lpm = 1;
+02604         dwc_write_reg32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32);
+02605 
+02606         return 0;
+02607 }
+02608 
+02609 #endif                          /* CONFIG_USB_DWC_OTG_LPM */
+02610 
+02611 int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port)
+02612 {
+02613         int retval;
+02614 
+02615         if (port != 1) {
+02616                 return -DWC_E_INVALID;
+02617         }
+02618 
+02619         retval = (hcd->flags.b.port_connect_status_change ||
+02620                   hcd->flags.b.port_reset_change ||
+02621                   hcd->flags.b.port_enable_change ||
+02622                   hcd->flags.b.port_suspend_change ||
+02623                   hcd->flags.b.port_over_current_change);
+02624 #ifdef DEBUG
+02625         if (retval) {
+02626                 DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB STATUS DATA:"
+02627                             " Root port status changed\n");
+02628                 DWC_DEBUGPL(DBG_HCDV, "  port_connect_status_change: %d\n",
+02629                             hcd->flags.b.port_connect_status_change);
+02630                 DWC_DEBUGPL(DBG_HCDV, "  port_reset_change: %d\n",
+02631                             hcd->flags.b.port_reset_change);
+02632                 DWC_DEBUGPL(DBG_HCDV, "  port_enable_change: %d\n",
+02633                             hcd->flags.b.port_enable_change);
+02634                 DWC_DEBUGPL(DBG_HCDV, "  port_suspend_change: %d\n",
+02635                             hcd->flags.b.port_suspend_change);
+02636                 DWC_DEBUGPL(DBG_HCDV, "  port_over_current_change: %d\n",
+02637                             hcd->flags.b.port_over_current_change);
+02638         }
+02639 #endif
+02640         return retval;
+02641 }
+02642 
+02643 int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * dwc_otg_hcd)
+02644 {
+02645         hfnum_data_t hfnum;
+02646         hfnum.d32 = dwc_read_reg32(&dwc_otg_hcd->core_if->
+02647                                    host_if->host_global_regs->hfnum);
+02648 
+02649 #ifdef DEBUG_SOF
+02650         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n",
+02651                     hfnum.b.frnum);
+02652 #endif
+02653         return hfnum.b.frnum;
+02654 }
+02655 
+02656 int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
+02657                       struct dwc_otg_hcd_function_ops *fops)
+02658 {
+02659         int retval = 0;
+02660 
+02661         hcd->fops = fops;
+02662         if (!dwc_otg_is_device_mode(hcd->core_if)) {
+02663                 dwc_otg_hcd_reinit(hcd);
+02664         } else {
+02665                 retval = -DWC_E_NO_DEVICE;
+02666         }
+02667 
+02668         return retval;
+02669 }
+02670 
+02671 void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd)
+02672 {
+02673         return hcd->priv;
+02674 }
+02675 
+02676 void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data)
+02677 {
+02678         hcd->priv = priv_data;
+02679 }
+02680 
+02681 uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd)
+02682 {
+02683         return hcd->otg_port;
+02684 }
+02685 
+02686 uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd)
+02687 {
+02688         uint32_t is_b_host;
+02689         if (hcd->core_if->op_state == B_HOST) {
+02690                 is_b_host = 1;
+02691         } else {
+02692                 is_b_host = 0;
+02693         }
+02694 
+02695         return is_b_host;
+02696 }
+02697 
+02698 dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
+02699                                          int iso_desc_count, int atomic_alloc)
+02700 {
+02701         dwc_otg_hcd_urb_t *dwc_otg_urb;
+02702         uint32_t size;
+02703 
+02704         size =
+02705             sizeof(*dwc_otg_urb) +
+02706             iso_desc_count * sizeof(struct dwc_otg_hcd_iso_packet_desc);
+02707         if (atomic_alloc) {
+02708                 dwc_otg_urb = dwc_alloc_atomic(size);
+02709         } else {
+02710                 dwc_otg_urb = dwc_alloc(size);
+02711         }
+02712         dwc_otg_urb->packet_count = iso_desc_count;
+02713 
+02714         return dwc_otg_urb;
+02715 }
+02716 
+02717 void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * dwc_otg_urb,
+02718                                   uint8_t dev_addr, uint8_t ep_num,
+02719                                   uint8_t ep_type, uint8_t ep_dir, uint16_t mps)
+02720 {
+02721         dwc_otg_hcd_fill_pipe(&dwc_otg_urb->pipe_info, dev_addr, ep_num,
+02722                               ep_type, ep_dir, mps);
+02723 #if 0
+02724         DWC_PRINTF
+02725             ("addr = %d, ep_num = %d, ep_dir = 0x%x, ep_type = 0x%x, mps = %d\n",
+02726              dev_addr, ep_num, ep_dir, ep_type, mps);
+02727 #endif
+02728 }
+02729 
+02730 void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
+02731                                 void *urb_handle, void *buf, dwc_dma_t dma,
+02732                                 uint32_t buflen, void *setup_packet,
+02733                                 dwc_dma_t setup_dma, uint32_t flags,
+02734                                 uint16_t interval)
+02735 {
+02736         dwc_otg_urb->priv = urb_handle;
+02737         dwc_otg_urb->buf = buf;
+02738         dwc_otg_urb->dma = dma;
+02739         dwc_otg_urb->length = buflen;
+02740         dwc_otg_urb->setup_packet = setup_packet;
+02741         dwc_otg_urb->setup_dma = setup_dma;
+02742         dwc_otg_urb->flags = flags;
+02743         dwc_otg_urb->interval = interval;
+02744         dwc_otg_urb->status = -DWC_E_IN_PROGRESS;
+02745 }
+02746 
+02747 uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb)
+02748 {
+02749         return dwc_otg_urb->status;
+02750 }
+02751 
+02752 uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t * dwc_otg_urb)
+02753 {
+02754         return dwc_otg_urb->actual_length;
+02755 }
+02756 
+02757 uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t * dwc_otg_urb)
+02758 {
+02759         return dwc_otg_urb->error_count;
+02760 }
+02761 
+02762 void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
+02763                                          int desc_num, uint32_t offset,
+02764                                          uint32_t length)
+02765 {
+02766         dwc_otg_urb->iso_descs[desc_num].offset = offset;
+02767         dwc_otg_urb->iso_descs[desc_num].length = length;
+02768 }
+02769 
+02770 uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t * dwc_otg_urb,
+02771                                              int desc_num)
+02772 {
+02773         return dwc_otg_urb->iso_descs[desc_num].status;
+02774 }
+02775 
+02776 uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
+02777                                                     dwc_otg_urb, int desc_num)
+02778 {
+02779         return dwc_otg_urb->iso_descs[desc_num].actual_length;
+02780 }
+02781 
+02782 int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd, void *ep_handle)
+02783 {
+02784         int allocated = 0;
+02785         dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
+02786 
+02787         if (qh) {
+02788                 if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
+02789                         allocated = 1;
+02790                 }
+02791         }
+02792         return allocated;
+02793 }
+02794 
+02795 int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle)
+02796 {
+02797         dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
+02798         int freed = 0;
+02799         DWC_ASSERT(qh, "qh is not allocated\n");
+02800 
+02801         if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
+02802                 freed = 1;
+02803         }
+02804 
+02805         return freed;
+02806 }
+02807 
+02808 uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd, void *ep_handle)
+02809 {
+02810         dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle;
+02811         DWC_ASSERT(qh, "qh is not allocated\n");
+02812         return qh->usecs;
+02813 }
+02814 
+02815 void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd)
+02816 {
+02817 #ifdef DEBUG
+02818         int num_channels;
+02819         int i;
+02820         gnptxsts_data_t np_tx_status;
+02821         hptxsts_data_t p_tx_status;
+02822 
+02823         num_channels = hcd->core_if->core_params->host_channels;
+02824         DWC_PRINTF("\n");
+02825         DWC_PRINTF
+02826             ("************************************************************\n");
+02827         DWC_PRINTF("HCD State:\n");
+02828         DWC_PRINTF("  Num channels: %d\n", num_channels);
+02829         for (i = 0; i < num_channels; i++) {
+02830                 dwc_hc_t *hc = hcd->hc_ptr_array[i];
+02831                 DWC_PRINTF("  Channel %d:\n", i);
+02832                 DWC_PRINTF("    dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
+02833                            hc->dev_addr, hc->ep_num, hc->ep_is_in);
+02834                 DWC_PRINTF("    speed: %d\n", hc->speed);
+02835                 DWC_PRINTF("    ep_type: %d\n", hc->ep_type);
+02836                 DWC_PRINTF("    max_packet: %d\n", hc->max_packet);
+02837                 DWC_PRINTF("    data_pid_start: %d\n", hc->data_pid_start);
+02838                 DWC_PRINTF("    multi_count: %d\n", hc->multi_count);
+02839                 DWC_PRINTF("    xfer_started: %d\n", hc->xfer_started);
+02840                 DWC_PRINTF("    xfer_buff: %p\n", hc->xfer_buff);
+02841                 DWC_PRINTF("    xfer_len: %d\n", hc->xfer_len);
+02842                 DWC_PRINTF("    xfer_count: %d\n", hc->xfer_count);
+02843                 DWC_PRINTF("    halt_on_queue: %d\n", hc->halt_on_queue);
+02844                 DWC_PRINTF("    halt_pending: %d\n", hc->halt_pending);
+02845                 DWC_PRINTF("    halt_status: %d\n", hc->halt_status);
+02846                 DWC_PRINTF("    do_split: %d\n", hc->do_split);
+02847                 DWC_PRINTF("    complete_split: %d\n", hc->complete_split);
+02848                 DWC_PRINTF("    hub_addr: %d\n", hc->hub_addr);
+02849                 DWC_PRINTF("    port_addr: %d\n", hc->port_addr);
+02850                 DWC_PRINTF("    xact_pos: %d\n", hc->xact_pos);
+02851                 DWC_PRINTF("    requests: %d\n", hc->requests);
+02852                 DWC_PRINTF("    qh: %p\n", hc->qh);
+02853                 if (hc->xfer_started) {
+02854                         hfnum_data_t hfnum;
+02855                         hcchar_data_t hcchar;
+02856                         hctsiz_data_t hctsiz;
+02857                         hcint_data_t hcint;
+02858                         hcintmsk_data_t hcintmsk;
+02859                         hfnum.d32 =
+02860                             dwc_read_reg32(&hcd->core_if->host_if->
+02861                                            host_global_regs->hfnum);
+02862                         hcchar.d32 =
+02863                             dwc_read_reg32(&hcd->core_if->host_if->hc_regs[i]->
+02864                                            hcchar);
+02865                         hctsiz.d32 =
+02866                             dwc_read_reg32(&hcd->core_if->host_if->hc_regs[i]->
+02867                                            hctsiz);
+02868                         hcint.d32 =
+02869                             dwc_read_reg32(&hcd->core_if->host_if->hc_regs[i]->
+02870                                            hcint);
+02871                         hcintmsk.d32 =
+02872                             dwc_read_reg32(&hcd->core_if->host_if->hc_regs[i]->
+02873                                            hcintmsk);
+02874                         DWC_PRINTF("    hfnum: 0x%08x\n", hfnum.d32);
+02875                         DWC_PRINTF("    hcchar: 0x%08x\n", hcchar.d32);
+02876                         DWC_PRINTF("    hctsiz: 0x%08x\n", hctsiz.d32);
+02877                         DWC_PRINTF("    hcint: 0x%08x\n", hcint.d32);
+02878                         DWC_PRINTF("    hcintmsk: 0x%08x\n", hcintmsk.d32);
+02879                 }
+02880                 if (hc->xfer_started && hc->qh) {
+02881                         dwc_otg_qtd_t *qtd;
+02882                         dwc_otg_hcd_urb_t *urb;
+02883                         
+02884                         DWC_CIRCLEQ_FOREACH(qtd, &hc->qh->qtd_list, qtd_list_entry) {
+02885                                 if(!qtd->in_process)
+02886                                         break;
+02887                                 
+02888                                 urb = qtd->urb;
+02889                         DWC_PRINTF("    URB Info:\n");
+02890                         DWC_PRINTF("      qtd: %p, urb: %p\n", qtd, urb);
+02891                         if (urb) {
+02892                                 DWC_PRINTF("      Dev: %d, EP: %d %s\n",
+02893                                            dwc_otg_hcd_get_dev_addr(&urb->
+02894                                                                     pipe_info),
+02895                                            dwc_otg_hcd_get_ep_num(&urb->
+02896                                                                   pipe_info),
+02897                                            dwc_otg_hcd_is_pipe_in(&urb->
+02898                                                                   pipe_info) ?
+02899                                            "IN" : "OUT");
+02900                                 DWC_PRINTF("      Max packet size: %d\n",
+02901                                            dwc_otg_hcd_get_mps(&urb->
+02902                                                                pipe_info));
+02903                                 DWC_PRINTF("      transfer_buffer: %p\n",
+02904                                            urb->buf);
+02905                                 DWC_PRINTF("      transfer_dma: %p\n",
+02906                                            (void *)urb->dma);
+02907                                 DWC_PRINTF("      transfer_buffer_length: %d\n",
+02908                                            urb->length);
+02909                                 DWC_PRINTF("      actual_length: %d\n",
+02910                                            urb->actual_length);
+02911                         }
+02912                 }
+02913         }
+02914         }
+02915         DWC_PRINTF("  non_periodic_channels: %d\n", hcd->non_periodic_channels);
+02916         DWC_PRINTF("  periodic_channels: %d\n", hcd->periodic_channels);
+02917         DWC_PRINTF("  periodic_usecs: %d\n", hcd->periodic_usecs);
+02918         np_tx_status.d32 =
+02919             dwc_read_reg32(&hcd->core_if->core_global_regs->gnptxsts);
+02920         DWC_PRINTF("  NP Tx Req Queue Space Avail: %d\n",
+02921                    np_tx_status.b.nptxqspcavail);
+02922         DWC_PRINTF("  NP Tx FIFO Space Avail: %d\n",
+02923                    np_tx_status.b.nptxfspcavail);
+02924         p_tx_status.d32 =
+02925             dwc_read_reg32(&hcd->core_if->host_if->host_global_regs->hptxsts);
+02926         DWC_PRINTF("  P Tx Req Queue Space Avail: %d\n",
+02927                    p_tx_status.b.ptxqspcavail);
+02928         DWC_PRINTF("  P Tx FIFO Space Avail: %d\n", p_tx_status.b.ptxfspcavail);
+02929         dwc_otg_hcd_dump_frrem(hcd);
+02930         dwc_otg_dump_global_registers(hcd->core_if);
+02931         dwc_otg_dump_host_registers(hcd->core_if);
+02932         DWC_PRINTF
+02933             ("************************************************************\n");
+02934         DWC_PRINTF("\n");
+02935 #endif
+02936 }
+02937 
+02938 #ifdef DEBUG
+02939 void dwc_print_setup_data(uint8_t * setup)
+02940 {
+02941         int i;
+02942         if (CHK_DEBUG_LEVEL(DBG_HCD)) {
+02943                 DWC_PRINTF("Setup Data = MSB ");
+02944                 for (i = 7; i >= 0; i--)
+02945                         DWC_PRINTF("%02x ", setup[i]);
+02946                 DWC_PRINTF("\n");
+02947                 DWC_PRINTF("  bmRequestType Tranfer = %s\n",
+02948                            (setup[0] & 0x80) ? "Device-to-Host" :
+02949                            "Host-to-Device");
+02950                 DWC_PRINTF("  bmRequestType Type = ");
+02951                 switch ((setup[0] & 0x60) >> 5) {
+02952                 case 0:
+02953                         DWC_PRINTF("Standard\n");
+02954                         break;
+02955                 case 1:
+02956                         DWC_PRINTF("Class\n");
+02957                         break;
+02958                 case 2:
+02959                         DWC_PRINTF("Vendor\n");
+02960                         break;
+02961                 case 3:
+02962                         DWC_PRINTF("Reserved\n");
+02963                         break;
+02964                 }
+02965                 DWC_PRINTF("  bmRequestType Recipient = ");
+02966                 switch (setup[0] & 0x1f) {
+02967                 case 0:
+02968                         DWC_PRINTF("Device\n");
+02969                         break;
+02970                 case 1:
+02971                         DWC_PRINTF("Interface\n");
+02972                         break;
+02973                 case 2:
+02974                         DWC_PRINTF("Endpoint\n");
+02975                         break;
+02976                 case 3:
+02977                         DWC_PRINTF("Other\n");
+02978                         break;
+02979                 default:
+02980                         DWC_PRINTF("Reserved\n");
+02981                         break;
+02982                 }
+02983                 DWC_PRINTF("  bRequest = 0x%0x\n", setup[1]);
+02984                 DWC_PRINTF("  wValue = 0x%0x\n", *((uint16_t *) & setup[2]));
+02985                 DWC_PRINTF("  wIndex = 0x%0x\n", *((uint16_t *) & setup[4]));
+02986                 DWC_PRINTF("  wLength = 0x%0x\n\n", *((uint16_t *) & setup[6]));
+02987         }
+02988 }
+02989 #endif
+02990 
+02991 void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd)
+02992 {
+02993 #if 0
+02994         DWC_PRINTF("Frame remaining at SOF:\n");
+02995         DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
+02996                    hcd->frrem_samples, hcd->frrem_accum,
+02997                    (hcd->frrem_samples > 0) ?
+02998                    hcd->frrem_accum / hcd->frrem_samples : 0);
+02999 
+03000         DWC_PRINTF("\n");
+03001         DWC_PRINTF("Frame remaining at start_transfer (uframe 7):\n");
+03002         DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
+03003                    hcd->core_if->hfnum_7_samples,
+03004                    hcd->core_if->hfnum_7_frrem_accum,
+03005                    (hcd->core_if->hfnum_7_samples >
+03006                     0) ? hcd->core_if->hfnum_7_frrem_accum /
+03007                    hcd->core_if->hfnum_7_samples : 0);
+03008         DWC_PRINTF("Frame remaining at start_transfer (uframe 0):\n");
+03009         DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
+03010                    hcd->core_if->hfnum_0_samples,
+03011                    hcd->core_if->hfnum_0_frrem_accum,
+03012                    (hcd->core_if->hfnum_0_samples >
+03013                     0) ? hcd->core_if->hfnum_0_frrem_accum /
+03014                    hcd->core_if->hfnum_0_samples : 0);
+03015         DWC_PRINTF("Frame remaining at start_transfer (uframe 1-6):\n");
+03016         DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
+03017                    hcd->core_if->hfnum_other_samples,
+03018                    hcd->core_if->hfnum_other_frrem_accum,
+03019                    (hcd->core_if->hfnum_other_samples >
+03020                     0) ? hcd->core_if->hfnum_other_frrem_accum /
+03021                    hcd->core_if->hfnum_other_samples : 0);
+03022 
+03023         DWC_PRINTF("\n");
+03024         DWC_PRINTF("Frame remaining at sample point A (uframe 7):\n");
+03025         DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
+03026                    hcd->hfnum_7_samples_a, hcd->hfnum_7_frrem_accum_a,
+03027                    (hcd->hfnum_7_samples_a > 0) ?
+03028                    hcd->hfnum_7_frrem_accum_a / hcd->hfnum_7_samples_a : 0);
+03029         DWC_PRINTF("Frame remaining at sample point A (uframe 0):\n");
+03030         DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
+03031                    hcd->hfnum_0_samples_a, hcd->hfnum_0_frrem_accum_a,
+03032                    (hcd->hfnum_0_samples_a > 0) ?
+03033                    hcd->hfnum_0_frrem_accum_a / hcd->hfnum_0_samples_a : 0);
+03034         DWC_PRINTF("Frame remaining at sample point A (uframe 1-6):\n");
+03035         DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
+03036                    hcd->hfnum_other_samples_a, hcd->hfnum_other_frrem_accum_a,
+03037                    (hcd->hfnum_other_samples_a > 0) ?
+03038                    hcd->hfnum_other_frrem_accum_a /
+03039                    hcd->hfnum_other_samples_a : 0);
+03040 
+03041         DWC_PRINTF("\n");
+03042         DWC_PRINTF("Frame remaining at sample point B (uframe 7):\n");
+03043         DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
+03044                    hcd->hfnum_7_samples_b, hcd->hfnum_7_frrem_accum_b,
+03045                    (hcd->hfnum_7_samples_b > 0) ?
+03046                    hcd->hfnum_7_frrem_accum_b / hcd->hfnum_7_samples_b : 0);
+03047         DWC_PRINTF("Frame remaining at sample point B (uframe 0):\n");
+03048         DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
+03049                    hcd->hfnum_0_samples_b, hcd->hfnum_0_frrem_accum_b,
+03050                    (hcd->hfnum_0_samples_b > 0) ?
+03051                    hcd->hfnum_0_frrem_accum_b / hcd->hfnum_0_samples_b : 0);
+03052         DWC_PRINTF("Frame remaining at sample point B (uframe 1-6):\n");
+03053         DWC_PRINTF("  samples %u, accum %llu, avg %llu\n",
+03054                    hcd->hfnum_other_samples_b, hcd->hfnum_other_frrem_accum_b,
+03055                    (hcd->hfnum_other_samples_b > 0) ?
+03056                    hcd->hfnum_other_frrem_accum_b /
+03057                    hcd->hfnum_other_samples_b : 0);
+03058 #endif
+03059 }
+03060 
+03061 #endif                          /* DWC_DEVICE_ONLY */
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd_8c.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd_8c.html new file mode 100644 index 000000000000..91f704b52ae9 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd_8c.html @@ -0,0 +1,1837 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hcd.c File Reference + + + + + + +

dwc_otg_hcd.c File Reference

This file implements HCD Core. More... +

+#include "dwc_otg_hcd.h"
+#include "dwc_otg_regs.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Functions

+dwc_otg_hcd_tdwc_otg_hcd_alloc_hcd (void)
 This function allocates dwc_otg_hcd structure and returns pointer on it.
void dwc_otg_hcd_connect_timeout (void *ptr)
 Connection timeout function.
static void hcd_start_func (void *_vp)
 Work queue function for starting the HCD when A-Cable is connected.
+static void del_xfer_timers (dwc_otg_hcd_t *hcd)
+static void del_timers (dwc_otg_hcd_t *hcd)
static void kill_urbs_in_qh_list (dwc_otg_hcd_t *hcd, dwc_list_link_t *qh_list)
 Processes all the URBs in a single list of QHs.
static void kill_all_urbs (dwc_otg_hcd_t *hcd)
 Responds with an error status of ETIMEDOUT to all URBs in the non-periodic and periodic schedules.
static void dwc_otg_hcd_start_connect_timer (dwc_otg_hcd_t *hcd)
 Start the connection timer.
static int32_t dwc_otg_hcd_session_start_cb (void *p)
 HCD Callback function for disconnect of the HCD.
static int32_t dwc_otg_hcd_start_cb (void *p)
 HCD Callback function for starting the HCD when A-Cable is connected.
static int32_t dwc_otg_hcd_disconnect_cb (void *p)
 HCD Callback function for disconnect of the HCD.
static int32_t dwc_otg_hcd_stop_cb (void *p)
 HCD Callback function for stopping the HCD.
static int dwc_otg_hcd_rem_wakeup_cb (void *p)
 HCD Callback function for Remote Wakeup.
void dwc_otg_hcd_stop (dwc_otg_hcd_t *hcd)
 Halts the DWC_otg host mode operations in a clean manner.
int dwc_otg_hcd_urb_enqueue (dwc_otg_hcd_t *hcd, dwc_otg_hcd_urb_t *dwc_otg_urb, void **ep_handle)
 Queue URB.
int dwc_otg_hcd_urb_dequeue (dwc_otg_hcd_t *hcd, dwc_otg_hcd_urb_t *dwc_otg_urb)
 De-queue the specified URB.
int dwc_otg_hcd_endpoint_disable (dwc_otg_hcd_t *hcd, void *ep_handle, int retry)
 Frees resources in the DWC_otg controller related to a given endpoint.
+static void reset_tasklet_func (void *data)
 Reset tasklet function.
+static void qh_list_free (dwc_otg_hcd_t *hcd, dwc_list_link_t *qh_list)
+static void dwc_otg_hcd_free (dwc_otg_hcd_t *dwc_otg_hcd)
 Frees secondary storage associated with the dwc_otg_hcd structure contained in the struct usb_hcd field.
int dwc_otg_hcd_init (dwc_otg_hcd_t *hcd, dwc_otg_core_if_t *core_if)
 This function should be called to initiate HCD Core.
void dwc_otg_hcd_remove (dwc_otg_hcd_t *hcd)
 Frees HCD.
+static void dwc_otg_hcd_reinit (dwc_otg_hcd_t *hcd)
 Initializes dynamic portions of the DWC_otg HCD state.
static void assign_and_init_hc (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
 Assigns transactions from a QTD to a free host channel and initializes the host channel to perform the transactions.
dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions (dwc_otg_hcd_t *hcd)
 This function selects transactions from the HCD transfer schedule and assigns them to available host channels.
static int queue_transaction (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, uint16_t fifo_dwords_avail)
 Attempts to queue a single transaction request for a host channel associated with either a periodic or non-periodic transfer.
static void process_periodic_channels (dwc_otg_hcd_t *hcd)
 Processes periodic channels for the next frame and queues transactions for these channels to the DWC_otg controller.
static void process_non_periodic_channels (dwc_otg_hcd_t *hcd)
 Processes active non-periodic channels and queues transactions for these channels to the DWC_otg controller.
void dwc_otg_hcd_queue_transactions (dwc_otg_hcd_t *hcd, dwc_otg_transaction_type_e tr_type)
 This function processes the currently active host channels and queues transactions for these channels to the DWC_otg controller.
int dwc_otg_hcd_hub_control (dwc_otg_hcd_t *dwc_otg_hcd, uint16_t typeReq, uint16_t wValue, uint16_t wIndex, uint8_t *buf, uint16_t wLength)
 Handles hub class-specific requests.
int dwc_otg_hcd_is_status_changed (dwc_otg_hcd_t *hcd, int port)
 Returns 1 if status of specified port is changed and 0 otherwise.
int dwc_otg_hcd_get_frame_number (dwc_otg_hcd_t *dwc_otg_hcd)
 Returns current frame number.
int dwc_otg_hcd_start (dwc_otg_hcd_t *hcd, struct dwc_otg_hcd_function_ops *fops)
 This function initializes the HCD Core.
void * dwc_otg_hcd_get_priv_data (dwc_otg_hcd_t *hcd)
 Returns private data set by dwc_otg_hcd_set_priv_data function.
void dwc_otg_hcd_set_priv_data (dwc_otg_hcd_t *hcd, void *priv_data)
 Set private data.
uint32_t dwc_otg_hcd_otg_port (dwc_otg_hcd_t *hcd)
 Returns otg port number.
uint32_t dwc_otg_hcd_is_b_host (dwc_otg_hcd_t *hcd)
 Returns 1 if currently core is acting as B host, and 0 otherwise.
dwc_otg_hcd_urb_tdwc_otg_hcd_urb_alloc (dwc_otg_hcd_t *hcd, int iso_desc_count, int atomic_alloc)
 Allocates memory for dwc_otg_hcd_urb structure.
void dwc_otg_hcd_urb_set_pipeinfo (dwc_otg_hcd_urb_t *dwc_otg_urb, uint8_t dev_addr, uint8_t ep_num, uint8_t ep_type, uint8_t ep_dir, uint16_t mps)
 Set pipe information in URB.
void dwc_otg_hcd_urb_set_params (dwc_otg_hcd_urb_t *dwc_otg_urb, void *urb_handle, void *buf, dwc_dma_t dma, uint32_t buflen, void *setup_packet, dwc_dma_t setup_dma, uint32_t flags, uint16_t interval)
 Sets dwc_otg_hcd_urb parameters.
uint32_t dwc_otg_hcd_urb_get_status (dwc_otg_hcd_urb_t *dwc_otg_urb)
 Gets status from dwc_otg_hcd_urb.
uint32_t dwc_otg_hcd_urb_get_actual_length (dwc_otg_hcd_urb_t *dwc_otg_urb)
 Gets actual length from dwc_otg_hcd_urb.
uint32_t dwc_otg_hcd_urb_get_error_count (dwc_otg_hcd_urb_t *dwc_otg_urb)
 Gets error count from dwc_otg_hcd_urb.
void dwc_otg_hcd_urb_set_iso_desc_params (dwc_otg_hcd_urb_t *dwc_otg_urb, int desc_num, uint32_t offset, uint32_t length)
 Set ISOC descriptor offset and length.
uint32_t dwc_otg_hcd_urb_get_iso_desc_status (dwc_otg_hcd_urb_t *dwc_otg_urb, int desc_num)
 Get status of ISOC descriptor, specified by desc_num.
uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length (dwc_otg_hcd_urb_t *dwc_otg_urb, int desc_num)
 Get actual length of ISOC descriptor, specified by desc_num.
int dwc_otg_hcd_is_bandwidth_allocated (dwc_otg_hcd_t *hcd, void *ep_handle)
 Call this function to check if bandwidth was allocated for specified endpoint.
int dwc_otg_hcd_is_bandwidth_freed (dwc_otg_hcd_t *hcd, void *ep_handle)
 Call this function to check if bandwidth was freed for specified endpoint.
uint8_t dwc_otg_hcd_get_ep_bandwidth (dwc_otg_hcd_t *hcd, void *ep_handle)
 Returns bandwidth allocated for specified endpoint in microseconds.
void dwc_otg_hcd_dump_state (dwc_otg_hcd_t *hcd)
 Dumps hcd state.
void dwc_otg_hcd_dump_frrem (dwc_otg_hcd_t *hcd)
 Dump the average frame remaining at SOF.

Variables

static dwc_otg_cil_callbacks_t hcd_cil_callbacks
 HCD Callback structure for handling mode switching.
+


Detailed Description

+This file implements HCD Core. +

+All code in this file is portable and don't use any OS specific functions. Interface provided by HCD Core is defined in <hcd_if.h> header file. +

+Definition in file dwc_otg_hcd.c.


Function Documentation

+ +
+
+ + + + + + + + + +
void dwc_otg_hcd_connect_timeout (void *  ptr  ) 
+
+
+ +

+Connection timeout function. +

+An OTG host is required to display a message if the device does not connect within 10 seconds. +

+Definition at line 54 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
static void hcd_start_func (void *  _vp  )  [static]
+
+
+ +

+Work queue function for starting the HCD when A-Cable is connected. +

+The hcd_start() must be called in a process context. +

+Definition at line 123 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static void kill_urbs_in_qh_list (dwc_otg_hcd_t hcd,
dwc_list_link_t *  qh_list 
) [static]
+
+
+ +

+Processes all the URBs in a single list of QHs. +

+Completes them with -ETIMEDOUT and frees the QTD. +

+Definition at line 154 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
static void kill_all_urbs (dwc_otg_hcd_t hcd  )  [static]
+
+
+ +

+Responds with an error status of ETIMEDOUT to all URBs in the non-periodic and periodic schedules. +

+The QTD associated with each URB is removed from the schedule and freed. This function may be called when a disconnect is detected or when the HCD is being stopped. +

+Definition at line 182 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
static void dwc_otg_hcd_start_connect_timer (dwc_otg_hcd_t hcd  )  [static]
+
+
+ +

+Start the connection timer. +

+An OTG host is required to display a message if the device does not connect within 10 seconds. The timer is deleted if a port connect interrupt occurs before the timer expires. +

+Definition at line 198 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
static int32_t dwc_otg_hcd_session_start_cb (void *  p  )  [static]
+
+
+ +

+HCD Callback function for disconnect of the HCD. +

+

Parameters:
+ + +
p void pointer to the struct usb_hcd
+
+ +

+Definition at line 208 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
static int32_t dwc_otg_hcd_start_cb (void *  p  )  [static]
+
+
+ +

+HCD Callback function for starting the HCD when A-Cable is connected. +

+

Parameters:
+ + +
p void pointer to the struct usb_hcd
+
+ +

+Definition at line 223 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
static int32_t dwc_otg_hcd_disconnect_cb (void *  p  )  [static]
+
+
+ +

+HCD Callback function for disconnect of the HCD. +

+

Parameters:
+ + +
p void pointer to the struct usb_hcd
+
+ +

+Definition at line 253 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
static int32_t dwc_otg_hcd_stop_cb (void *  p  )  [static]
+
+
+ +

+HCD Callback function for stopping the HCD. +

+

Parameters:
+ + +
p void pointer to the struct usb_hcd
+
+ +

+Definition at line 373 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
static int dwc_otg_hcd_rem_wakeup_cb (void *  p  )  [static]
+
+
+ +

+HCD Callback function for Remote Wakeup. +

+

Parameters:
+ + +
p void pointer to the struct usb_hcd
+
+ +

+Definition at line 403 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_hcd_stop (dwc_otg_hcd_t hcd  ) 
+
+
+ +

+Halts the DWC_otg host mode operations in a clean manner. +

+USB transfers are stopped. +

+Definition at line 422 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_urb_enqueue (dwc_otg_hcd_t dwc_otg_hcd,
dwc_otg_hcd_urb_t dwc_otg_urb,
void **  ep_handle 
)
+
+
+ +

+Queue URB. +

+After transfer is completes, the complete callback will be called with the URB status

+

Parameters:
+ + + + +
dwc_otg_hcd The HCD
dwc_otg_urb DWC_OTG URB
ep_handle Out parameter for returning endpoint handle
+
+Returns -DWC_E_NO_DEVICE if no device is connected. Returns -DWC_E_NO_MEMORY if there is no enough memory. Returns 0 on success. +

+Definition at line 444 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_urb_dequeue (dwc_otg_hcd_t dwc_otg_hcd,
dwc_otg_hcd_urb_t dwc_otg_urb 
)
+
+
+ +

+De-queue the specified URB. +

+

Parameters:
+ + + +
dwc_otg_hcd The HCD
dwc_otg_urb DWC_OTG URB
+
+ +

+Definition at line 489 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_endpoint_disable (dwc_otg_hcd_t hcd,
void *  ep_handle,
int  retry 
)
+
+
+ +

+Frees resources in the DWC_otg controller related to a given endpoint. +

+Any URBs for the endpoint must already be dequeued.

+

Parameters:
+ + + + +
hcd The HCD
ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
retry Number of retries if there are queued transfers.
+
+Returns -DWC_E_INVALID if invalid arguments are passed. Returns 0 on success +

+Definition at line 547 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_init (dwc_otg_hcd_t hcd,
dwc_otg_core_if_t core_if 
)
+
+
+ +

+This function should be called to initiate HCD Core. +

+

Parameters:
+ + + +
hcd The HCD
core_if The DWC_OTG Core
+
+Returns -DWC_E_NO_MEMORY if no enough memory. Returns 0 on success +

+Definition at line 693 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_hcd_remove (dwc_otg_hcd_t hcd  ) 
+
+
+ +

+Frees HCD. +

+

Parameters:
+ + +
hcd The HCD
+
+ +

+Definition at line 778 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static void assign_and_init_hc (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh 
) [static]
+
+
+ +

+Assigns transactions from a QTD to a free host channel and initializes the host channel to perform the transactions. +

+The host channel is removed from the free list.

+

Parameters:
+ + + +
hcd The HCD state structure.
qh Transactions from the first QTD for this QH are selected and assigned to a free host channel.
+
+ +

+Definition at line 832 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions (dwc_otg_hcd_t hcd  ) 
+
+
+ +

+This function selects transactions from the HCD transfer schedule and assigns them to available host channels. +

+It is called from HCD interrupt handler functions.

+

Parameters:
+ + +
hcd The HCD state structure.
+
+
Returns:
The types of new transactions that were assigned to host channels.
+ +

+Definition at line 1055 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
static int queue_transaction (dwc_otg_hcd_t hcd,
dwc_hc_t hc,
uint16_t  fifo_dwords_avail 
) [static]
+
+
+ +

+Attempts to queue a single transaction request for a host channel associated with either a periodic or non-periodic transfer. +

+This function assumes that there is space available in the appropriate request queue. For an OUT transfer or SETUP transaction in Slave mode, it checks whether space is available in the appropriate Tx FIFO.

+

Parameters:
+ + + + +
hcd The HCD state structure.
hc Host channel descriptor associated with either a periodic or non-periodic transfer.
fifo_dwords_avail Number of DWORDs available in the periodic Tx FIFO for periodic transfers or the non-periodic Tx FIFO for non-periodic transfers.
+
+
Returns:
1 if a request is queued and more requests may be needed to complete the transfer, 0 if no more requests are required for this transfer, -1 if there is insufficient space in the Tx FIFO.
+ +

+Definition at line 1139 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
static void process_periodic_channels (dwc_otg_hcd_t hcd  )  [static]
+
+
+ +

+Processes periodic channels for the next frame and queues transactions for these channels to the DWC_otg controller. +

+After queueing transactions, the Periodic Tx FIFO Empty interrupt is enabled if there are more transactions to queue as Periodic Tx FIFO or request queue space becomes available. Otherwise, the Periodic Tx FIFO Empty interrupt is disabled. +

+Definition at line 1199 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
static void process_non_periodic_channels (dwc_otg_hcd_t hcd  )  [static]
+
+
+ +

+Processes active non-periodic channels and queues transactions for these channels to the DWC_otg controller. +

+After queueing transactions, the NP Tx FIFO Empty interrupt is enabled if there are more transactions to queue as NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx FIFO Empty interrupt is disabled. +

+Definition at line 1316 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_queue_transactions (dwc_otg_hcd_t hcd,
dwc_otg_transaction_type_e  tr_type 
)
+
+
+ +

+This function processes the currently active host channels and queues transactions for these channels to the DWC_otg controller. +

+It is called from HCD interrupt handler functions.

+

Parameters:
+ + + +
hcd The HCD state structure.
tr_type The type(s) of transactions to queue (non-periodic, periodic, or both).
+
+ +

+Definition at line 1426 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_hub_control (dwc_otg_hcd_t dwc_otg_hcd,
uint16_t  typeReq,
uint16_t  wValue,
uint16_t  wIndex,
uint8_t *  buf,
uint16_t  wLength 
)
+
+
+ +

+Handles hub class-specific requests. +

+

Parameters:
+ + + + + + + +
dwc_otg_hcd The HCD
typeReq Request Type
wValue wValue from control request
wIndex wIndex from control request
buf data buffer
wLength data buffer length
+
+Returns -DWC_E_INVALID if invalid argument is passed Returns 0 on success +

+Definition at line 1905 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_is_status_changed (dwc_otg_hcd_t hcd,
int  port 
)
+
+
+ +

+Returns 1 if status of specified port is changed and 0 otherwise. +

+

Parameters:
+ + + +
hcd The HCD
port Port number
+
+ +

+Definition at line 2611 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
int dwc_otg_hcd_get_frame_number (dwc_otg_hcd_t hcd  ) 
+
+
+ +

+Returns current frame number. +

+

Parameters:
+ + +
hcd The HCD
+
+ +

+Definition at line 2643 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_start (dwc_otg_hcd_t hcd,
struct dwc_otg_hcd_function_ops fops 
)
+
+
+ +

+This function initializes the HCD Core. +

+

Parameters:
+ + + +
hcd The HCD
fops The Function Driver Operations data structure containing pointers to all callbacks.
+
+Returns -DWC_E_NO_DEVICE if Core is currently is in device mode. Returns 0 on success +

+Definition at line 2656 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
void* dwc_otg_hcd_get_priv_data (dwc_otg_hcd_t hcd  ) 
+
+
+ +

+Returns private data set by dwc_otg_hcd_set_priv_data function. +

+

Parameters:
+ + +
hcd The HCD
+
+ +

+Definition at line 2671 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_set_priv_data (dwc_otg_hcd_t hcd,
void *  priv_data 
)
+
+
+ +

+Set private data. +

+

Parameters:
+ + + +
hcd The HCD
priv_data pointer to be stored in private data
+
+ +

+Definition at line 2676 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
uint32_t dwc_otg_hcd_otg_port (dwc_otg_hcd_t hcd  ) 
+
+
+ +

+Returns otg port number. +

+

Parameters:
+ + +
hcd The HCD
+
+ +

+Definition at line 2681 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
uint32_t dwc_otg_hcd_is_b_host (dwc_otg_hcd_t hcd  ) 
+
+
+ +

+Returns 1 if currently core is acting as B host, and 0 otherwise. +

+

Parameters:
+ + +
hcd The HCD
+
+ +

+Definition at line 2686 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
dwc_otg_hcd_urb_t* dwc_otg_hcd_urb_alloc (dwc_otg_hcd_t hcd,
int  iso_desc_count,
int  atomic_alloc 
)
+
+
+ +

+Allocates memory for dwc_otg_hcd_urb structure. +

+Allocated memory should be freed by call dwc_free function.

+

Parameters:
+ + + + +
hcd The HCD
iso_desc_count Count of ISOC descriptors
atomic_alloc Specefies whether to perform atomic allocation.
+
+ +

+Definition at line 2698 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_urb_set_pipeinfo (dwc_otg_hcd_urb_t hcd_urb,
uint8_t  devaddr,
uint8_t  ep_num,
uint8_t  ep_type,
uint8_t  ep_dir,
uint16_t  mps 
)
+
+
+ +

+Set pipe information in URB. +

+

Parameters:
+ + + + + + + +
hcd_urb DWC_OTG URB
devaddr Device Address
ep_num Endpoint Number
ep_type Endpoint Type
ep_dir Endpoint Direction
mps Max Packet Size
+
+ +

+Definition at line 2717 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_urb_set_params (dwc_otg_hcd_urb_t urb,
void *  urb_handle,
void *  buf,
dwc_dma_t  dma,
uint32_t  buflen,
void *  sp,
dwc_dma_t  sp_dma,
uint32_t  flags,
uint16_t  interval 
)
+
+
+ +

+Sets dwc_otg_hcd_urb parameters. +

+

Parameters:
+ + + + + + + + + + +
urb DWC_OTG URB allocated by dwc_otg_hcd_urb_alloc function.
urb_handle Unique handle for request, this will be passed back to function driver in completion callback.
buf The buffer for the data
dma The DMA buffer for the data
buflen Transfer length
sp Buffer for setup data
sp_dma DMA address of setup data buffer
flags Transfer flags
interval Polling interval for interrupt or isochronous transfers.
+
+ +

+Definition at line 2730 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
uint32_t dwc_otg_hcd_urb_get_status (dwc_otg_hcd_urb_t dwc_otg_urb  ) 
+
+
+ +

+Gets status from dwc_otg_hcd_urb. +

+

Parameters:
+ + +
dwc_otg_urb DWC_OTG URB
+
+ +

+Definition at line 2747 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
uint32_t dwc_otg_hcd_urb_get_actual_length (dwc_otg_hcd_urb_t dwc_otg_urb  ) 
+
+
+ +

+Gets actual length from dwc_otg_hcd_urb. +

+

Parameters:
+ + +
dwc_otg_urb DWC_OTG URB
+
+ +

+Definition at line 2752 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
uint32_t dwc_otg_hcd_urb_get_error_count (dwc_otg_hcd_urb_t dwc_otg_urb  ) 
+
+
+ +

+Gets error count from dwc_otg_hcd_urb. +

+Only for ISOC URBs

+

Parameters:
+ + +
dwc_otg_urb DWC_OTG URB
+
+ +

+Definition at line 2757 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_urb_set_iso_desc_params (dwc_otg_hcd_urb_t dwc_otg_urb,
int  desc_num,
uint32_t  offset,
uint32_t  length 
)
+
+
+ +

+Set ISOC descriptor offset and length. +

+

Parameters:
+ + + + + +
dwc_otg_urb DWC_OTG URB
desc_num ISOC descriptor number
offset Offset from beginig of buffer.
length Transaction length
+
+ +

+Definition at line 2762 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
uint32_t dwc_otg_hcd_urb_get_iso_desc_status (dwc_otg_hcd_urb_t dwc_otg_urb,
int  desc_num 
)
+
+
+ +

+Get status of ISOC descriptor, specified by desc_num. +

+

Parameters:
+ + + +
dwc_otg_urb DWC_OTG URB
desc_num ISOC descriptor number
+
+ +

+Definition at line 2770 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length (dwc_otg_hcd_urb_t dwc_otg_urb,
int  desc_num 
)
+
+
+ +

+Get actual length of ISOC descriptor, specified by desc_num. +

+

Parameters:
+ + + +
dwc_otg_urb DWC_OTG URB
desc_num ISOC descriptor number
+
+ +

+Definition at line 2776 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_is_bandwidth_allocated (dwc_otg_hcd_t hcd,
void *  ep_handle 
)
+
+
+ +

+Call this function to check if bandwidth was allocated for specified endpoint. +

+Only for ISOC and INTERRUPT endpoints.

+

Parameters:
+ + + +
hcd The HCD
ep_handle Endpoint handle
+
+ +

+Definition at line 2782 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_is_bandwidth_freed (dwc_otg_hcd_t hcd,
void *  ep_handle 
)
+
+
+ +

+Call this function to check if bandwidth was freed for specified endpoint. +

+

Parameters:
+ + + +
hcd The HCD
ep_handle Endpoint handle
+
+ +

+Definition at line 2795 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
uint8_t dwc_otg_hcd_get_ep_bandwidth (dwc_otg_hcd_t hcd,
void *  ep_handle 
)
+
+
+ +

+Returns bandwidth allocated for specified endpoint in microseconds. +

+Only for ISOC and INTERRUPT endpoints.

+

Parameters:
+ + + +
hcd The HCD
ep_handle Endpoint handle
+
+ +

+Definition at line 2808 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_hcd_dump_state (dwc_otg_hcd_t hcd  ) 
+
+
+ +

+Dumps hcd state. +

+

Parameters:
+ + +
hcd The HCD
+
+ +

+Definition at line 2815 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_hcd_dump_frrem (dwc_otg_hcd_t hcd  ) 
+
+
+ +

+Dump the average frame remaining at SOF. +

+This can be used to determine average interrupt latency. Frame remaining is also shown for start transfer and two additional sample points. Currently this function is not implemented.

+

Parameters:
+ + +
hcd The HCD
+
+ +

+Definition at line 2991 of file dwc_otg_hcd.c. +

+

+


Variable Documentation

+ +
+ +
+ +

+Initial value:

 {
+        .start = dwc_otg_hcd_start_cb,
+        .stop = dwc_otg_hcd_stop_cb,
+        .disconnect = dwc_otg_hcd_disconnect_cb,
+        .session_start = dwc_otg_hcd_session_start_cb,
+        .resume_wakeup = dwc_otg_hcd_rem_wakeup_cb,
+
+
+
+        .p = 0,
+}
+
HCD Callback structure for handling mode switching. +

+ +

+Definition at line 590 of file dwc_otg_hcd.c. +

+

+


Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd_8h-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd_8h-source.html new file mode 100644 index 000000000000..2012c64ce994 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd_8h-source.html @@ -0,0 +1,517 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hcd.h Source File + + + + + + +

dwc_otg_hcd.h

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.h $
+00003  * $Revision: #52 $
+00004  * $Date: 2009/04/21 $
+00005  * $Change: 1237472 $
+00006  *
+00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009  * otherwise expressly agreed to in writing between Synopsys and you.
+00010  *
+00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012  * any End User Software License Agreement or Agreement for Licensed Product
+00013  * with Synopsys or any supplement thereto. You are permitted to use and
+00014  * redistribute this Software in source and binary forms, with or without
+00015  * modification, provided that redistributions of source code must retain this
+00016  * notice. You may not view, use, disclose, copy or distribute this file or
+00017  * any information contained herein except pursuant to this license grant from
+00018  * Synopsys. If you do not agree with this notice, including the disclaimer
+00019  * below, then you are not authorized to use the Software.
+00020  *
+00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031  * DAMAGE.
+00032  * ========================================================================== */
+00033 #ifndef DWC_DEVICE_ONLY
+00034 #ifndef __DWC_HCD_H__
+00035 #define __DWC_HCD_H__
+00036 
+00037 #include <usb.h>
+00038 #include "dwc_otg_hcd_if.h"
+00039 #include "dwc_otg_core_if.h"
+00040 #include "dwc_list.h"
+00041 #include "dwc_otg_cil.h"
+00042 
+00055 struct dwc_otg_hcd_pipe_info {
+00056         uint8_t dev_addr;
+00057         uint8_t ep_num;
+00058         uint8_t pipe_type;
+00059         uint8_t pipe_dir;
+00060         uint16_t mps;
+00061 };
+00062 
+00063 struct dwc_otg_hcd_iso_packet_desc {
+00064         uint32_t offset;
+00065         uint32_t length;
+00066         uint32_t actual_length;
+00067         uint32_t status;
+00068 };
+00069 
+00070 struct dwc_otg_qtd;
+00071 
+00072 struct dwc_otg_hcd_urb {
+00073         void *priv;
+00074         struct dwc_otg_qtd *qtd;
+00075         void *buf;
+00076         dwc_dma_t dma;
+00077         void *setup_packet;
+00078         dwc_dma_t setup_dma;
+00079         uint32_t length;
+00080         uint32_t actual_length;
+00081         uint32_t status;
+00082         uint32_t error_count;
+00083         uint32_t packet_count;
+00084         uint32_t flags;
+00085         uint16_t interval;
+00086         struct dwc_otg_hcd_pipe_info pipe_info;
+00087         struct dwc_otg_hcd_iso_packet_desc iso_descs[0];
+00088 };
+00089 
+00090 static inline uint8_t dwc_otg_hcd_get_ep_num(struct dwc_otg_hcd_pipe_info *pipe)
+00091 {
+00092         return pipe->ep_num;
+00093 }
+00094 
+00095 static inline uint8_t dwc_otg_hcd_get_pipe_type(struct dwc_otg_hcd_pipe_info
+00096                                                 *pipe)
+00097 {
+00098         return pipe->pipe_type;
+00099 }
+00100 
+00101 static inline uint16_t dwc_otg_hcd_get_mps(struct dwc_otg_hcd_pipe_info *pipe)
+00102 {
+00103         return pipe->mps;
+00104 }
+00105 
+00106 static inline uint8_t dwc_otg_hcd_get_dev_addr(struct dwc_otg_hcd_pipe_info
+00107                                                *pipe)
+00108 {
+00109         return pipe->dev_addr;
+00110 }
+00111 
+00112 static inline uint8_t dwc_otg_hcd_is_pipe_isoc(struct dwc_otg_hcd_pipe_info
+00113                                                *pipe)
+00114 {
+00115         return (pipe->pipe_type == UE_ISOCHRONOUS);
+00116 }
+00117 
+00118 static inline uint8_t dwc_otg_hcd_is_pipe_int(struct dwc_otg_hcd_pipe_info
+00119                                               *pipe)
+00120 {
+00121         return (pipe->pipe_type == UE_INTERRUPT);
+00122 }
+00123 
+00124 static inline uint8_t dwc_otg_hcd_is_pipe_bulk(struct dwc_otg_hcd_pipe_info
+00125                                                *pipe)
+00126 {
+00127         return (pipe->pipe_type == UE_BULK);
+00128 }
+00129 
+00130 static inline uint8_t dwc_otg_hcd_is_pipe_control(struct dwc_otg_hcd_pipe_info
+00131                                                   *pipe)
+00132 {
+00133         return (pipe->pipe_type == UE_CONTROL);
+00134 }
+00135 
+00136 static inline uint8_t dwc_otg_hcd_is_pipe_in(struct dwc_otg_hcd_pipe_info *pipe)
+00137 {
+00138         return (pipe->pipe_dir == UE_DIR_IN);
+00139 }
+00140 
+00141 static inline uint8_t dwc_otg_hcd_is_pipe_out(struct dwc_otg_hcd_pipe_info
+00142                                               *pipe)
+00143 {
+00144         return (!dwc_otg_hcd_is_pipe_in(pipe));
+00145 }
+00146 
+00147 static inline void dwc_otg_hcd_fill_pipe(struct dwc_otg_hcd_pipe_info *pipe,
+00148                                          uint8_t devaddr, uint8_t ep_num,
+00149                                          uint8_t pipe_type, uint8_t pipe_dir,
+00150                                          uint16_t mps)
+00151 {
+00152         pipe->dev_addr = devaddr;
+00153         pipe->ep_num = ep_num;
+00154         pipe->pipe_type = pipe_type;
+00155         pipe->pipe_dir = pipe_dir;
+00156         pipe->mps = mps;
+00157 }
+00158 
+00162 typedef enum dwc_otg_control_phase {
+00163         DWC_OTG_CONTROL_SETUP,
+00164         DWC_OTG_CONTROL_DATA,
+00165         DWC_OTG_CONTROL_STATUS
+00166 } dwc_otg_control_phase_e;
+00167 
+00169 typedef enum dwc_otg_transaction_type {
+00170         DWC_OTG_TRANSACTION_NONE,
+00171         DWC_OTG_TRANSACTION_PERIODIC,
+00172         DWC_OTG_TRANSACTION_NON_PERIODIC,
+00173         DWC_OTG_TRANSACTION_ALL
+00174 } dwc_otg_transaction_type_e;
+00175 
+00176 struct dwc_otg_qh;
+00177 
+00191 typedef struct dwc_otg_qtd {
+00199         uint8_t data_toggle;
+00200 
+00202         dwc_otg_control_phase_e control_phase;
+00203 
+00206         uint8_t complete_split;
+00207 
+00209         uint32_t ssplit_out_xfer_count;
+00210 
+00215         uint8_t error_count;
+00216 
+00224         uint16_t isoc_frame_index;
+00225 
+00227         uint8_t isoc_split_pos;
+00228 
+00230         uint16_t isoc_split_offset;
+00231 
+00233         struct dwc_otg_hcd_urb *urb;
+00234 
+00235         struct dwc_otg_qh *qh;
+00236 
+00238          DWC_CIRCLEQ_ENTRY(dwc_otg_qtd) qtd_list_entry;
+00239 
+00241         uint8_t in_process;
+00242 
+00244         uint8_t n_desc;
+00245         
+00250         uint16_t isoc_frame_index_last;
+00251         
+00252 } dwc_otg_qtd_t;
+00253 
+00254 DWC_CIRCLEQ_HEAD(dwc_otg_qtd_list, dwc_otg_qtd);
+00255 
+00261 typedef struct dwc_otg_qh {
+00270         uint8_t ep_type;
+00271         uint8_t ep_is_in;
+00272 
+00274         uint16_t maxp;
+00275 
+00283         uint8_t dev_speed;
+00284 
+00292         uint8_t data_toggle;
+00293 
+00295         uint8_t ping_state;
+00296 
+00300         struct dwc_otg_qtd_list qtd_list;
+00301 
+00303         struct dwc_hc *channel;
+00304 
+00306         uint8_t do_split;
+00307 
+00312         uint16_t usecs;
+00313 
+00315         uint16_t interval;
+00316 
+00321         uint16_t sched_frame;
+00322 
+00324         uint16_t start_split_frame;
+00325 
+00332         uint8_t *dw_align_buf;
+00333         dwc_dma_t dw_align_buf_dma;
+00334         
+00336         dwc_list_link_t qh_list_entry;
+00337         
+00342         dwc_otg_host_dma_desc_t *desc_list;
+00343         
+00345         dwc_dma_t desc_list_dma;
+00346         
+00352         uint32_t *n_bytes;
+00353         
+00355         uint16_t ntd;
+00356         
+00358         uint8_t td_first;
+00360         uint8_t td_last;
+00361         
+00364 } dwc_otg_qh_t;
+00365 
+00366 DWC_CIRCLEQ_HEAD(hc_list, dwc_hc);
+00367 
+00372 struct dwc_otg_hcd {
+00374         dwc_otg_core_if_t *core_if;
+00375 
+00377         struct dwc_otg_hcd_function_ops *fops;
+00378 
+00380         volatile union dwc_otg_hcd_internal_flags {
+00381                 uint32_t d32;
+00382                 struct {
+00383                         unsigned port_connect_status_change:1;
+00384                         unsigned port_connect_status:1;
+00385                         unsigned port_reset_change:1;
+00386                         unsigned port_enable_change:1;
+00387                         unsigned port_suspend_change:1;
+00388                         unsigned port_over_current_change:1;
+00389                         unsigned port_l1_change:1;
+00390                         unsigned reserved:26;
+00391                 } b;
+00392         } flags;
+00393 
+00399         dwc_list_link_t non_periodic_sched_inactive;
+00400 
+00406         dwc_list_link_t non_periodic_sched_active;
+00407 
+00412         dwc_list_link_t *non_periodic_qh_ptr;
+00413 
+00428         dwc_list_link_t periodic_sched_inactive;
+00429 
+00437         dwc_list_link_t periodic_sched_ready;
+00438 
+00446         dwc_list_link_t periodic_sched_assigned;
+00447 
+00457         dwc_list_link_t periodic_sched_queued;
+00458 
+00464         uint16_t periodic_usecs;
+00465 
+00470         uint16_t frame_number;
+00471 
+00476         struct hc_list free_hc_list;
+00483         int periodic_channels;
+00484 
+00488         int non_periodic_channels;
+00489 
+00495         struct dwc_hc *hc_ptr_array[MAX_EPS_CHANNELS];
+00496 
+00502         uint8_t *status_buf;
+00503 
+00507         dma_addr_t status_buf_dma;
+00508 #define DWC_OTG_HCD_STATUS_BUF_SIZE 64
+00509 
+00515         dwc_timer_t *conn_timer;
+00516 
+00517         /* Tasket to do a reset */
+00518         dwc_tasklet_t *reset_tasklet;
+00519 
+00520         /*  */
+00521         dwc_spinlock_t *lock;
+00522 
+00526         void *priv;
+00527 
+00528         uint8_t otg_port;
+00529 
+00531         uint32_t *frame_list;
+00532 
+00534         dma_addr_t frame_list_dma;
+00535 
+00536 #ifdef DEBUG
+00537         uint32_t frrem_samples;
+00538         uint64_t frrem_accum;
+00539 
+00540         uint32_t hfnum_7_samples_a;
+00541         uint64_t hfnum_7_frrem_accum_a;
+00542         uint32_t hfnum_0_samples_a;
+00543         uint64_t hfnum_0_frrem_accum_a;
+00544         uint32_t hfnum_other_samples_a;
+00545         uint64_t hfnum_other_frrem_accum_a;
+00546 
+00547         uint32_t hfnum_7_samples_b;
+00548         uint64_t hfnum_7_frrem_accum_b;
+00549         uint32_t hfnum_0_samples_b;
+00550         uint64_t hfnum_0_frrem_accum_b;
+00551         uint32_t hfnum_other_samples_b;
+00552         uint64_t hfnum_other_frrem_accum_b;
+00553 #endif
+00554 };
+00555 
+00558 extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t
+00559                                                                   * hcd);
+00560 extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
+00561                                     dwc_otg_transaction_type_e tr_type);
+00562 
+00567 extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
+00568 extern int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * dwc_otg_hcd);
+00569 extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t *
+00570                                                          dwc_otg_hcd);
+00571 extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t *
+00572                                                         dwc_otg_hcd);
+00573 extern int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t *
+00574                                                            dwc_otg_hcd);
+00575 extern int32_t dwc_otg_hcd_handle_incomplete_periodic_intr(dwc_otg_hcd_t *
+00576                                                            dwc_otg_hcd);
+00577 extern int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd);
+00578 extern int32_t dwc_otg_hcd_handle_conn_id_status_change_intr(dwc_otg_hcd_t *
+00579                                                              dwc_otg_hcd);
+00580 extern int32_t dwc_otg_hcd_handle_disconnect_intr(dwc_otg_hcd_t * dwc_otg_hcd);
+00581 extern int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd);
+00582 extern int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd,
+00583                                             uint32_t num);
+00584 extern int32_t dwc_otg_hcd_handle_session_req_intr(dwc_otg_hcd_t * dwc_otg_hcd);
+00585 extern int32_t dwc_otg_hcd_handle_wakeup_detected_intr(dwc_otg_hcd_t *
+00586                                                        dwc_otg_hcd);
+00592 /* Implemented in dwc_otg_hcd_queue.c */
+00593 extern dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
+00594                                            dwc_otg_hcd_urb_t * urb);
+00595 extern void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
+00596 extern int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
+00597 extern void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
+00598 extern void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
+00599                                       int sched_csplit);
+00600 
+00602 static inline void dwc_otg_hcd_qh_remove_and_free(dwc_otg_hcd_t * hcd,
+00603                                                   dwc_otg_qh_t * qh)
+00604 {
+00605         dwc_otg_hcd_qh_remove(hcd, qh);
+00606         dwc_otg_hcd_qh_free(hcd, qh);
+00607 }
+00608 
+00611 static inline dwc_otg_qh_t *dwc_otg_hcd_qh_alloc(void)
+00612 {
+00613         return (dwc_otg_qh_t *) dwc_alloc(sizeof(dwc_otg_qh_t));
+00614 }
+00615 
+00616 extern dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb);
+00617 extern void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb);
+00618 extern int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, dwc_otg_hcd_t * dwc_otg_hcd,
+00619                                dwc_otg_qh_t ** qh);
+00620 
+00623 static inline dwc_otg_qtd_t *dwc_otg_hcd_qtd_alloc(void)
+00624 {
+00625         return (dwc_otg_qtd_t *) dwc_alloc(sizeof(dwc_otg_qtd_t));
+00626 }
+00627 
+00631 static inline void dwc_otg_hcd_qtd_free(dwc_otg_qtd_t * qtd)
+00632 {
+00633         dwc_free(qtd);
+00634 }
+00635 
+00641 static inline void dwc_otg_hcd_qtd_remove(dwc_otg_hcd_t * hcd,
+00642                                           dwc_otg_qtd_t * qtd,
+00643                                           dwc_otg_qh_t * qh)
+00644 {
+00645         uint64_t flags;
+00646         DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
+00647         DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
+00648         DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
+00649 }
+00650 
+00652 static inline void dwc_otg_hcd_qtd_remove_and_free(dwc_otg_hcd_t * hcd,
+00653                                                    dwc_otg_qtd_t * qtd,
+00654                                                    dwc_otg_qh_t * qh)
+00655 {
+00656         dwc_otg_hcd_qtd_remove(hcd, qtd, qh);
+00657         dwc_otg_hcd_qtd_free(qtd);
+00658 }
+00659 
+00665 extern void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
+00666 extern void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd,
+00667                                            dwc_hc_t * hc,
+00668                                            dwc_otg_hc_regs_t * hc_regs,
+00669                                            dwc_otg_halt_status_e halt_status);
+00670 
+00671 extern int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
+00672 extern void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh);
+00673 
+00678 dwc_otg_qh_t *dwc_urb_to_qh(dwc_otg_hcd_urb_t * urb);
+00681 #ifdef CONFIG_USB_DWC_OTG_LPM
+00682 extern int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd,
+00683                                            uint8_t devaddr);
+00684 extern void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd);
+00685 #endif
+00686 
+00688 #define dwc_list_to_qh(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qh_t, qh_list_entry)
+00689 
+00691 #define dwc_list_to_qtd(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qtd_t, qtd_list_entry)
+00692 
+00694 #define dwc_qh_is_non_per(_qh_ptr_) ((_qh_ptr_->ep_type == UE_BULK) || \
+00695                                      (_qh_ptr_->ep_type == UE_CONTROL))
+00696 
+00698 #define dwc_hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+00699 
+00701 #define dwc_max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
+00702 
+00708 static inline int dwc_frame_num_le(uint16_t frame1, uint16_t frame2)
+00709 {
+00710         return ((frame2 - frame1) & DWC_HFNUM_MAX_FRNUM) <=
+00711             (DWC_HFNUM_MAX_FRNUM >> 1);
+00712 }
+00713 
+00719 static inline int dwc_frame_num_gt(uint16_t frame1, uint16_t frame2)
+00720 {
+00721         return (frame1 != frame2) &&
+00722             (((frame1 - frame2) & DWC_HFNUM_MAX_FRNUM) <
+00723              (DWC_HFNUM_MAX_FRNUM >> 1));
+00724 }
+00725 
+00730 static inline uint16_t dwc_frame_num_inc(uint16_t frame, uint16_t inc)
+00731 {
+00732         return (frame + inc) & DWC_HFNUM_MAX_FRNUM;
+00733 }
+00734 
+00735 static inline uint16_t dwc_full_frame_num(uint16_t frame)
+00736 {
+00737         return (frame & DWC_HFNUM_MAX_FRNUM) >> 3;
+00738 }
+00739 
+00740 static inline uint16_t dwc_micro_frame_num(uint16_t frame)
+00741 {
+00742         return frame & 0x7;
+00743 }
+00744 
+00745 void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
+00746                                   dwc_otg_hc_regs_t * hc_regs, 
+00747                                   dwc_otg_qtd_t * qtd);
+00748 
+00749 #ifdef DEBUG
+00750 
+00759 #define dwc_sample_frrem(_hcd, _qh, _letter) \
+00760 { \
+00761         hfnum_data_t hfnum; \
+00762         dwc_otg_qtd_t *qtd; \
+00763         qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); \
+00764         if (usb_pipeint(qtd->urb->pipe) && _qh->start_split_frame != 0 && !qtd->complete_split) { \
+00765                 hfnum.d32 = dwc_read_reg32(&_hcd->core_if->host_if->host_global_regs->hfnum); \
+00766                 switch (hfnum.b.frnum & 0x7) { \
+00767                 case 7: \
+00768                         _hcd->hfnum_7_samples_##_letter++; \
+00769                         _hcd->hfnum_7_frrem_accum_##_letter += hfnum.b.frrem; \
+00770                         break; \
+00771                 case 0: \
+00772                         _hcd->hfnum_0_samples_##_letter++; \
+00773                         _hcd->hfnum_0_frrem_accum_##_letter += hfnum.b.frrem; \
+00774                         break; \
+00775                 default: \
+00776                         _hcd->hfnum_other_samples_##_letter++; \
+00777                         _hcd->hfnum_other_frrem_accum_##_letter += hfnum.b.frrem; \
+00778                         break; \
+00779                 } \
+00780         } \
+00781 }
+00782 #else
+00783 #define dwc_sample_frrem(_hcd, _qh, _letter)
+00784 #endif
+00785 #endif
+00786 #endif                          /* DWC_DEVICE_ONLY */
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd_8h.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd_8h.html new file mode 100644 index 000000000000..66fd651465a2 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd_8h.html @@ -0,0 +1,1310 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hcd.h File Reference + + + + + + +

dwc_otg_hcd.h File Reference

This file contains the structures, constants, and interfaces for the Host Contoller Driver (HCD). More... +

+#include <usb.h>
+#include "dwc_otg_hcd_if.h"
+#include "dwc_otg_core_if.h"
+#include "dwc_list.h"
+#include "dwc_otg_cil.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Structures

struct  dwc_otg_hcd_pipe_info
struct  dwc_otg_hcd_iso_packet_desc
struct  dwc_otg_hcd_urb
struct  dwc_otg_qtd
 A Queue Transfer Descriptor (QTD) holds the state of a bulk, control, interrupt, or isochronous transfer. More...
struct  dwc_otg_qh
 A Queue Head (QH) holds the static characteristics of an endpoint and maintains a list of transfers (QTDs) for that endpoint. More...
struct  dwc_otg_hcd
 This structure holds the state of the HCD, including the non-periodic and periodic schedules. More...
union  dwc_otg_hcd::dwc_otg_hcd_internal_flags
 Internal DWC HCD Flags. More...

Transaction Execution Functions

dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions (dwc_otg_hcd_t *hcd)
 This function selects transactions from the HCD transfer schedule and assigns them to available host channels.
void dwc_otg_hcd_queue_transactions (dwc_otg_hcd_t *hcd, dwc_otg_transaction_type_e tr_type)
 This function processes the currently active host channels and queues transactions for these channels to the DWC_otg controller.

Interrupt Handler Functions

int32_t dwc_otg_hcd_handle_intr (dwc_otg_hcd_t *dwc_otg_hcd)
 This function handles interrupts for the HCD.
int32_t dwc_otg_hcd_handle_sof_intr (dwc_otg_hcd_t *dwc_otg_hcd)
 Handles the start-of-frame interrupt in host mode.
int32_t dwc_otg_hcd_handle_rx_status_q_level_intr (dwc_otg_hcd_t *dwc_otg_hcd)
 Handles the Rx Status Queue Level Interrupt, which indicates that there is at least one packet in the Rx FIFO.
int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr (dwc_otg_hcd_t *dwc_otg_hcd)
 This interrupt occurs when the non-periodic Tx FIFO is half-empty.
int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr (dwc_otg_hcd_t *dwc_otg_hcd)
 This interrupt occurs when the periodic Tx FIFO is half-empty.
+int32_t dwc_otg_hcd_handle_incomplete_periodic_intr (dwc_otg_hcd_t *dwc_otg_hcd)
int32_t dwc_otg_hcd_handle_port_intr (dwc_otg_hcd_t *dwc_otg_hcd)
 There are multiple conditions that can cause a port interrupt.
+int32_t dwc_otg_hcd_handle_conn_id_status_change_intr (dwc_otg_hcd_t *dwc_otg_hcd)
+int32_t dwc_otg_hcd_handle_disconnect_intr (dwc_otg_hcd_t *dwc_otg_hcd)
int32_t dwc_otg_hcd_handle_hc_intr (dwc_otg_hcd_t *dwc_otg_hcd)
 This interrupt indicates that one or more host channels has a pending interrupt.
+int32_t dwc_otg_hcd_handle_hc_n_intr (dwc_otg_hcd_t *dwc_otg_hcd, uint32_t num)
 Handles interrupt for a specific Host Channel.
+int32_t dwc_otg_hcd_handle_session_req_intr (dwc_otg_hcd_t *dwc_otg_hcd)
+int32_t dwc_otg_hcd_handle_wakeup_detected_intr (dwc_otg_hcd_t *dwc_otg_hcd)

Schedule Queue Functions

dwc_otg_qh_tdwc_otg_hcd_qh_create (dwc_otg_hcd_t *hcd, dwc_otg_hcd_urb_t *urb)
 This function allocates and initializes a QH.
void dwc_otg_hcd_qh_free (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
 Free each QTD in the QH's QTD-list then free the QH.
int dwc_otg_hcd_qh_add (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
 This function adds a QH to either the non periodic or periodic schedule if it is not already in the schedule.
void dwc_otg_hcd_qh_remove (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
 Removes a QH from either the non-periodic or periodic schedule.
void dwc_otg_hcd_qh_deactivate (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, int sched_csplit)
 Deactivates a QH.
+static void dwc_otg_hcd_qh_remove_and_free (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
 Remove and free a QH.
static dwc_otg_qh_tdwc_otg_hcd_qh_alloc (void)
 Allocates memory for a QH structure.
dwc_otg_qtd_tdwc_otg_hcd_qtd_create (dwc_otg_hcd_urb_t *urb)
 This function allocates and initializes a QTD.
void dwc_otg_hcd_qtd_init (dwc_otg_qtd_t *qtd, dwc_otg_hcd_urb_t *urb)
 Initializes a QTD structure.
int dwc_otg_hcd_qtd_add (dwc_otg_qtd_t *qtd, dwc_otg_hcd_t *dwc_otg_hcd, dwc_otg_qh_t **qh)
 This function adds a QTD to the QTD-list of a QH.
static dwc_otg_qtd_tdwc_otg_hcd_qtd_alloc (void)
 Allocates memory for a QTD structure.
static void dwc_otg_hcd_qtd_free (dwc_otg_qtd_t *qtd)
 Frees the memory for a QTD structure.
static void dwc_otg_hcd_qtd_remove (dwc_otg_hcd_t *hcd, dwc_otg_qtd_t *qtd, dwc_otg_qh_t *qh)
 Removes a QTD from list.
+static void dwc_otg_hcd_qtd_remove_and_free (dwc_otg_hcd_t *hcd, dwc_otg_qtd_t *qtd, dwc_otg_qh_t *qh)
 Remove and free a QTD.

Descriptor DMA Supporting Functions

void dwc_otg_hcd_start_xfer_ddma (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
 For Control and Bulk endpoints initializes descriptor list and starts the transfer.
void dwc_otg_hcd_complete_xfer_ddma (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_halt_status_e halt_status)
 This function is called from interrupt handlers.
int dwc_otg_hcd_qh_init_ddma (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
 Initializes a QH structure's Descriptor DMA related members.
void dwc_otg_hcd_qh_free_ddma (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
 Frees descriptor list memory associated with the QH.

Internal Functions

+dwc_otg_qh_tdwc_urb_to_qh (dwc_otg_hcd_urb_t *urb)

Defines

+#define DWC_OTG_HCD_STATUS_BUF_SIZE   64
+#define dwc_list_to_qh(_list_head_ptr_)   container_of(_list_head_ptr_, dwc_otg_qh_t, qh_list_entry)
 Gets the QH that contains the list_head.
+#define dwc_list_to_qtd(_list_head_ptr_)   container_of(_list_head_ptr_, dwc_otg_qtd_t, qtd_list_entry)
 Gets the QTD that contains the list_head.
#define dwc_qh_is_non_per(_qh_ptr_)
 Check if QH is non-periodic.
+#define dwc_hb_mult(wMaxPacketSize)   (1 + (((wMaxPacketSize) >> 11) & 0x03))
 High bandwidth multiplier as encoded in highspeed endpoint descriptors.
+#define dwc_max_packet(wMaxPacketSize)   ((wMaxPacketSize) & 0x07ff)
 Packet size for any kind of endpoint descriptor.
+#define dwc_sample_frrem(_hcd, _qh, _letter)

Typedefs

+typedef enum dwc_otg_control_phase dwc_otg_control_phase_e
 Phases for control transfers.
+typedef enum dwc_otg_transaction_type dwc_otg_transaction_type_e
 Transaction types.
typedef dwc_otg_qtd dwc_otg_qtd_t
 A Queue Transfer Descriptor (QTD) holds the state of a bulk, control, interrupt, or isochronous transfer.
typedef dwc_otg_qh dwc_otg_qh_t
 A Queue Head (QH) holds the static characteristics of an endpoint and maintains a list of transfers (QTDs) for that endpoint.

Enumerations

enum  dwc_otg_control_phase { DWC_OTG_CONTROL_SETUP, +DWC_OTG_CONTROL_DATA, +DWC_OTG_CONTROL_STATUS + }
 Phases for control transfers.
enum  dwc_otg_transaction_type { DWC_OTG_TRANSACTION_NONE, +DWC_OTG_TRANSACTION_PERIODIC, +DWC_OTG_TRANSACTION_NON_PERIODIC, +DWC_OTG_TRANSACTION_ALL + }
 Transaction types.

Functions

+static uint8_t dwc_otg_hcd_get_ep_num (struct dwc_otg_hcd_pipe_info *pipe)
+static uint8_t dwc_otg_hcd_get_pipe_type (struct dwc_otg_hcd_pipe_info *pipe)
+static uint16_t dwc_otg_hcd_get_mps (struct dwc_otg_hcd_pipe_info *pipe)
+static uint8_t dwc_otg_hcd_get_dev_addr (struct dwc_otg_hcd_pipe_info *pipe)
+static uint8_t dwc_otg_hcd_is_pipe_isoc (struct dwc_otg_hcd_pipe_info *pipe)
+static uint8_t dwc_otg_hcd_is_pipe_int (struct dwc_otg_hcd_pipe_info *pipe)
+static uint8_t dwc_otg_hcd_is_pipe_bulk (struct dwc_otg_hcd_pipe_info *pipe)
+static uint8_t dwc_otg_hcd_is_pipe_control (struct dwc_otg_hcd_pipe_info *pipe)
+static uint8_t dwc_otg_hcd_is_pipe_in (struct dwc_otg_hcd_pipe_info *pipe)
+static uint8_t dwc_otg_hcd_is_pipe_out (struct dwc_otg_hcd_pipe_info *pipe)
+static void dwc_otg_hcd_fill_pipe (struct dwc_otg_hcd_pipe_info *pipe, uint8_t devaddr, uint8_t ep_num, uint8_t pipe_type, uint8_t pipe_dir, uint16_t mps)
DWC_CIRCLEQ_HEAD (dwc_otg_qtd_list, dwc_otg_qtd)
DWC_CIRCLEQ_HEAD (hc_list, dwc_hc)
static int dwc_frame_num_le (uint16_t frame1, uint16_t frame2)
 Returns true if _frame1 is less than or equal to _frame2.
static int dwc_frame_num_gt (uint16_t frame1, uint16_t frame2)
 Returns true if _frame1 is greater than _frame2.
static uint16_t dwc_frame_num_inc (uint16_t frame, uint16_t inc)
 Increments _frame by the amount specified by _inc.
+static uint16_t dwc_full_frame_num (uint16_t frame)
+static uint16_t dwc_micro_frame_num (uint16_t frame)
+void dwc_otg_hcd_save_data_toggle (dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_qtd_t *qtd)
+


Detailed Description

+This file contains the structures, constants, and interfaces for the Host Contoller Driver (HCD). +

+The Host Controller Driver (HCD) is responsible for translating requests from the USB Driver into the appropriate actions on the DWC_otg controller. It isolates the USBD from the specifics of the controller by providing an API to the USBD. +

+Definition in file dwc_otg_hcd.h.


Define Documentation

+ +
+
+ + + + + + + + + +
#define dwc_qh_is_non_per (_qh_ptr_   ) 
+
+
+ +

+Value:

((_qh_ptr_->ep_type == UE_BULK) || \
+                                     (_qh_ptr_->ep_type == UE_CONTROL))
+
Check if QH is non-periodic. +

+ +

+Definition at line 694 of file dwc_otg_hcd.h. +

+

+


Typedef Documentation

+ +
+
+ + + + +
typedef struct dwc_otg_qtd dwc_otg_qtd_t
+
+
+ +

+A Queue Transfer Descriptor (QTD) holds the state of a bulk, control, interrupt, or isochronous transfer. +

+A single QTD is created for each URB (of one of these types) submitted to the HCD. The transfer associated with a QTD may require one or multiple transactions.

+A QTD is linked to a Queue Head, which is entered in either the non-periodic or periodic schedule for execution. When a QTD is chosen for execution, some or all of its transactions may be executed. After execution, the state of the QTD is updated. The QTD may be retired if all its transactions are complete or if an error occurred. Otherwise, it remains in the schedule so more transactions can be executed later. +

+

+ +

+
+ + + + +
typedef struct dwc_otg_qh dwc_otg_qh_t
+
+
+ +

+A Queue Head (QH) holds the static characteristics of an endpoint and maintains a list of transfers (QTDs) for that endpoint. +

+A QH structure may be entered in either the non-periodic or periodic schedule. +

+

+


Function Documentation

+ +
+
+ + + + + + + + + +
dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions (dwc_otg_hcd_t hcd  ) 
+
+
+ +

+This function selects transactions from the HCD transfer schedule and assigns them to available host channels. +

+It is called from HCD interrupt handler functions.

+

Parameters:
+ + +
hcd The HCD state structure.
+
+
Returns:
The types of new transactions that were assigned to host channels.
+ +

+Definition at line 1055 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_queue_transactions (dwc_otg_hcd_t hcd,
dwc_otg_transaction_type_e  tr_type 
)
+
+
+ +

+This function processes the currently active host channels and queues transactions for these channels to the DWC_otg controller. +

+It is called from HCD interrupt handler functions.

+

Parameters:
+ + + +
hcd The HCD state structure.
tr_type The type(s) of transactions to queue (non-periodic, periodic, or both).
+
+ +

+Definition at line 1426 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_hcd_handle_intr (dwc_otg_hcd_t dwc_otg_hcd  ) 
+
+
+ +

+This function handles interrupts for the HCD. +

+ +

+

Todo:
Implement i2cintr handler.
+ +

+Definition at line 43 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_hcd_handle_sof_intr (dwc_otg_hcd_t hcd  ) 
+
+
+ +

+Handles the start-of-frame interrupt in host mode. +

+Non-periodic transactions may be queued to the DWC_otg controller for the current (micro)frame. Periodic transactions may be queued to the controller for the next (micro)frame. +

+Definition at line 169 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_hcd_handle_rx_status_q_level_intr (dwc_otg_hcd_t dwc_otg_hcd  ) 
+
+
+ +

+Handles the Rx Status Queue Level Interrupt, which indicates that there is at least one packet in the Rx FIFO. +

+The packets are moved from the FIFO to memory if the DWC_otg controller is operating in Slave mode. +

+Definition at line 222 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr (dwc_otg_hcd_t dwc_otg_hcd  ) 
+
+
+ +

+This interrupt occurs when the non-periodic Tx FIFO is half-empty. +

+More data packets may be written to the FIFO for OUT transfers. More requests may be written to the non-periodic request queue for IN transfers. This interrupt is enabled only in Slave mode. +

+Definition at line 271 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr (dwc_otg_hcd_t dwc_otg_hcd  ) 
+
+
+ +

+This interrupt occurs when the periodic Tx FIFO is half-empty. +

+More data packets may be written to the FIFO for OUT transfers. More requests may be written to the periodic request queue for IN transfers. This interrupt is enabled only in Slave mode. +

+Definition at line 283 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_hcd_handle_port_intr (dwc_otg_hcd_t dwc_otg_hcd  ) 
+
+
+ +

+There are multiple conditions that can cause a port interrupt. +

+This function determines which interrupt conditions have occurred and handles them appropriately. +

+Overcurrent Change Interrupt +

+Definition at line 294 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_hcd_handle_hc_intr (dwc_otg_hcd_t dwc_otg_hcd  ) 
+
+
+ +

+This interrupt indicates that one or more host channels has a pending interrupt. +

+There are multiple conditions that can cause each host channel interrupt. This function determines which conditions have occurred for each host channel interrupt and handles them appropriately. +

+Definition at line 453 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
dwc_otg_qh_t* dwc_otg_hcd_qh_create (dwc_otg_hcd_t hcd,
dwc_otg_hcd_urb_t urb 
)
+
+
+ +

+This function allocates and initializes a QH. +

+

Parameters:
+ + + +
hcd The HCD state structure for the DWC OTG controller.
urb Holds the information about the device/endpoint that we need to initialize the QH.
+
+
Returns:
Returns pointer to the newly allocated QH, or NULL on error.
+ +

+

Todo:
add memflags argument
+ +

+Definition at line 296 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_qh_free (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh 
)
+
+
+ +

+Free each QTD in the QH's QTD-list then free the QH. +

+QH should already be removed from a list. QTD list should already be empty if called from URB Dequeue.

+

Parameters:
+ + + +
hcd HCD instance.
qh The QH to free.
+
+ +

+Definition at line 53 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_qh_add (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh 
)
+
+
+ +

+This function adds a QH to either the non periodic or periodic schedule if it is not already in the schedule. +

+If the QH is already in the schedule, no action is taken.

+

Returns:
0 if successful, negative error code otherwise.
+ +

+Definition at line 472 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_qh_remove (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh 
)
+
+
+ +

+Removes a QH from either the non-periodic or periodic schedule. +

+Memory is not freed.

+

Parameters:
+ + + +
hcd The HCD state structure.
qh QH to remove from schedule.
+
+ +

+Definition at line 522 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_qh_deactivate (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh,
int  sched_next_periodic_split 
)
+
+
+ +

+Deactivates a QH. +

+For non-periodic QHs, removes the QH from the active non-periodic schedule. The QH is added to the inactive non-periodic schedule if any QTDs are still attached to the QH.

+For periodic QHs, the QH is removed from the periodic queued schedule. If there are any QTDs still attached to the QH, the QH is added to either the periodic inactive schedule or the periodic ready schedule and its next scheduled frame is calculated. The QH is placed in the ready schedule if the scheduled frame has been reached already. Otherwise it's placed in the inactive schedule. If there are no QTDs attached to the QH, the QH is completely removed from the periodic schedule. +

+Definition at line 559 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + +
static dwc_otg_qh_t* dwc_otg_hcd_qh_alloc (void   )  [inline, static]
+
+
+ +

+Allocates memory for a QH structure. +

+

Returns:
Returns the memory allocate or NULL on error.
+ +

+Definition at line 611 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + + + + + + +
dwc_otg_qtd_t* dwc_otg_hcd_qtd_create (dwc_otg_hcd_urb_t urb  ) 
+
+
+ +

+This function allocates and initializes a QTD. +

+

Parameters:
+ + +
urb The URB to create a QTD from. Each URB-QTD pair will end up pointing to each other so each pair should have a unique correlation.
+
+
Returns:
Returns pointer to the newly allocated QTD, or NULL on error.
+ +

+Definition at line 643 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_qtd_init (dwc_otg_qtd_t qtd,
dwc_otg_hcd_urb_t urb 
)
+
+
+ +

+Initializes a QTD structure. +

+

Parameters:
+ + + +
qtd The QTD to initialize.
urb The URB to use for initialization.
+
+ +

+Definition at line 661 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_qtd_add (dwc_otg_qtd_t qtd,
dwc_otg_hcd_t hcd,
dwc_otg_qh_t **  qh 
)
+
+
+ +

+This function adds a QTD to the QTD-list of a QH. +

+It will find the correct QH to place the QTD into. If it does not find a QH, then it will create a new QH. If the QH to which the QTD is added is not currently scheduled, it is placed into the proper schedule based on its EP type.

+

Parameters:
+ + + + +
[in] qtd The QTD to add
[in] hcd The DWC HCD structure
[out] qh out parameter to return queue head
+
+
Returns:
0 if successful, negative error code otherwise.
+ +

+Definition at line 698 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + +
static dwc_otg_qtd_t* dwc_otg_hcd_qtd_alloc (void   )  [inline, static]
+
+
+ +

+Allocates memory for a QTD structure. +

+

Returns:
Returns the memory allocate or NULL on error.
+ +

+Definition at line 623 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + + + + + + +
static void dwc_otg_hcd_qtd_free (dwc_otg_qtd_t qtd  )  [inline, static]
+
+
+ +

+Frees the memory for a QTD structure. +

+QTD should already be removed from list.

Parameters:
+ + +
qtd QTD to free.
+
+ +

+Definition at line 631 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
static void dwc_otg_hcd_qtd_remove (dwc_otg_hcd_t hcd,
dwc_otg_qtd_t qtd,
dwc_otg_qh_t qh 
) [inline, static]
+
+
+ +

+Removes a QTD from list. +

+

Parameters:
+ + + + +
hcd HCD instance.
qtd QTD to remove from list.
qh QTD belongs to.
+
+ +

+Definition at line 641 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_start_xfer_ddma (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh 
)
+
+
+ +

+For Control and Bulk endpoints initializes descriptor list and starts the transfer. +

+For Interrupt and Isochronous endpoints initializes descriptor list then updates FrameList, marking appropriate entries as active. In case of Isochronous, the starting descriptor index is calculated based on the scheduled frame, but only on the first transfer descriptor within a session. Then starts the transfer via enabling the channel. For Isochronous endpoint the channel is not halted on XferComplete interrupt so remains assigned to the endpoint(QH) until session is done.

+

Parameters:
+ + + +
hcd The HCD state structure for the DWC OTG controller.
qh The QH to init.
+
+
Returns:
0 if successful, negative error code otherwise.
+ +

+Definition at line 675 of file dwc_otg_hcd_ddma.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_complete_xfer_ddma (dwc_otg_hcd_t hcd,
dwc_hc_t hc,
dwc_otg_hc_regs_t hc_regs,
dwc_otg_halt_status_e  halt_status 
)
+
+
+ +

+This function is called from interrupt handlers. +

+Scans the descriptor list, updates URB's status and calls completion routine for the URB if it's done. Releases the channel to be used by other transfers. In case of Isochronous endpoint the channel is not halted until the end of the session, i.e. QTD list is empty. If periodic channel released the FrameList is updated accordingly.

+Calls transaction selection routines to activate pending transfers.

+

Parameters:
+ + + + + +
hcd The HCD state structure for the DWC OTG controller.
hc Host channel, the transfer is completed on.
hc_regs Host channel registers.
halt_status Reason the channel is being halted, or just XferComplete for isochronous transfer
+
+ +

+

Todo:
Consider the case when period exceeds FrameList size. Frame Rollover interrupt should be used.
+ +

+Definition at line 1042 of file dwc_otg_hcd_ddma.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_qh_init_ddma (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh 
)
+
+
+ +

+Initializes a QH structure's Descriptor DMA related members. +

+Allocates memory for descriptor list. On first periodic QH, allocates memory for FrameList and enables periodic scheduling.

+

Parameters:
+ + + +
hcd The HCD state structure for the DWC OTG controller.
qh The QH to init.
+
+
Returns:
0 if successful, negative error code otherwise.
+ +

+Definition at line 294 of file dwc_otg_hcd_ddma.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_qh_free_ddma (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh 
)
+
+
+ +

+Frees descriptor list memory associated with the QH. +

+If QH is periodic and the last, frees FrameList memory and disables periodic scheduling.

+

Parameters:
+ + + +
hcd The HCD state structure for the DWC OTG controller.
qh The QH to init.
+
+ +

+Definition at line 327 of file dwc_otg_hcd_ddma.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static int dwc_frame_num_le (uint16_t  frame1,
uint16_t  frame2 
) [inline, static]
+
+
+ +

+Returns true if _frame1 is less than or equal to _frame2. +

+The comparison is done modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the frame number when the max frame number is reached. +

+Definition at line 708 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static int dwc_frame_num_gt (uint16_t  frame1,
uint16_t  frame2 
) [inline, static]
+
+
+ +

+Returns true if _frame1 is greater than _frame2. +

+The comparison is done modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the frame number when the max frame number is reached. +

+Definition at line 719 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static uint16_t dwc_frame_num_inc (uint16_t  frame,
uint16_t  inc 
) [inline, static]
+
+
+ +

+Increments _frame by the amount specified by _inc. +

+The addition is done modulo DWC_HFNUM_MAX_FRNUM. Returns the incremented value. +

+Definition at line 730 of file dwc_otg_hcd.h. +

+

+


Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__ddma_8c-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__ddma_8c-source.html new file mode 100644 index 000000000000..261dc561267b --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__ddma_8c-source.html @@ -0,0 +1,1070 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hcd_ddma.c Source File + + + + + + +

dwc_otg_hcd_ddma.c

Go to the documentation of this file.
00001 /*==========================================================================
+00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_ddma.c $
+00003  * $Revision: #2 $
+00004  * $Date: 2009/04/21 $
+00005  * $Change: 1237473 $
+00006  *
+00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009  * otherwise expressly agreed to in writing between Synopsys and you.
+00010  *
+00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012  * any End User Software License Agreement or Agreement for Licensed Product
+00013  * with Synopsys or any supplement thereto. You are permitted to use and
+00014  * redistribute this Software in source and binary forms, with or without
+00015  * modification, provided that redistributions of source code must retain this
+00016  * notice. You may not view, use, disclose, copy or distribute this file or
+00017  * any information contained herein except pursuant to this license grant from
+00018  * Synopsys. If you do not agree with this notice, including the disclaimer
+00019  * below, then you are not authorized to use the Software.
+00020  *
+00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031  * DAMAGE.
+00032  * ========================================================================== */
+00033 #ifndef DWC_DEVICE_ONLY
+00034 
+00039 #include "dwc_otg_hcd.h"
+00040 #include "dwc_otg_regs.h"
+00041                 
+00042                 
+00043 static inline uint8_t frame_list_idx(uint16_t frame)
+00044 {
+00045         return (frame & (MAX_FRLIST_EN_NUM - 1));
+00046 }
+00047 
+00048 static inline uint16_t desclist_idx_inc(uint16_t idx, uint16_t inc, uint8_t speed)
+00049 {
+00050         return (idx + inc) & 
+00051                 (((speed == DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC) - 1);
+00052 }
+00053 
+00054 static inline uint16_t desclist_idx_dec(uint16_t idx, uint16_t inc, uint8_t speed)
+00055 {
+00056         return (idx - inc) & 
+00057                 (((speed == DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC) - 1);
+00058 }
+00059 
+00060 static inline uint16_t max_desc_num(dwc_otg_qh_t * qh)
+00061 {
+00062         return (((qh->ep_type == UE_ISOCHRONOUS) && (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH)) 
+00063                                                         ?
+00064                                                         MAX_DMA_DESC_NUM_HS_ISOC
+00065                                                         :
+00066                                                         MAX_DMA_DESC_NUM_GENERIC);
+00067 }
+00068 static inline uint16_t frame_incr_val(dwc_otg_qh_t * qh)
+00069 {
+00070         return ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) 
+00071                                                 ? ((qh->interval + 8 - 1) / 8)
+00072                                                 :
+00073                                                 qh->interval);
+00074 }
+00075 
+00076 static int desc_list_alloc(dwc_otg_qh_t * qh)
+00077 {
+00078         int retval = 0;
+00079         
+00080         qh->desc_list = (dwc_otg_host_dma_desc_t *) 
+00081                                 dwc_dma_alloc(sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh),
+00082                                               &qh->desc_list_dma
+00083                                               );
+00084         
+00085         if (!qh->desc_list) {
+00086                 retval = -DWC_E_NO_MEMORY;
+00087                 DWC_ERROR("%s: DMA descriptor list allocation failed\n", __func__);
+00088                 
+00089         }
+00090         
+00091         dwc_memset(qh->desc_list, 0x00, sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
+00092          
+00093 
+00094         qh->n_bytes = (uint32_t *) dwc_alloc(sizeof(uint32_t) * max_desc_num(qh));
+00095         
+00096         if (!qh->n_bytes) {
+00097                 retval = -DWC_E_NO_MEMORY;
+00098                 DWC_ERROR("%s: Failed to allocate array for descriptors' size actual values\n",
+00099                           __func__);
+00100                 
+00101         }       
+00102         return retval;
+00103 
+00104 }
+00105 
+00106 static void desc_list_free(dwc_otg_qh_t * qh)
+00107 {
+00108         if(qh->desc_list) {
+00109                 dwc_dma_free(max_desc_num(qh), qh->desc_list, qh->desc_list_dma);
+00110                 qh->desc_list = NULL;
+00111         }
+00112         
+00113         if (qh->n_bytes) {
+00114                 dwc_free(qh->n_bytes);
+00115                 qh->n_bytes = NULL;
+00116         }
+00117 }
+00118 
+00119 static int frame_list_alloc(dwc_otg_hcd_t * hcd)
+00120 {
+00121         int retval = 0; 
+00122         if (hcd->frame_list)
+00123                 return 0;
+00124         
+00125         hcd->frame_list = dwc_dma_alloc(4 * MAX_FRLIST_EN_NUM,
+00126                                         &hcd->frame_list_dma
+00127                                         );
+00128         if (!hcd->frame_list) {
+00129                 retval = -DWC_E_NO_MEMORY;
+00130                 DWC_ERROR("%s: Frame List allocation failed\n", __func__);
+00131         }
+00132         
+00133         dwc_memset(hcd->frame_list, 0x00, 4 * MAX_FRLIST_EN_NUM);
+00134         
+00135         return retval;
+00136 }
+00137 
+00138 static void frame_list_free(dwc_otg_hcd_t * hcd)
+00139 {
+00140         if (!hcd->frame_list)
+00141                 return;
+00142         
+00143         dwc_dma_free(4 * MAX_FRLIST_EN_NUM, hcd->frame_list, hcd->frame_list_dma);
+00144         hcd->frame_list = NULL;
+00145 }
+00146 
+00147 static void per_sched_enable(dwc_otg_hcd_t * hcd, uint16_t fr_list_en)
+00148 {
+00149                 
+00150         hcfg_data_t hcfg;
+00151 
+00152         hcfg.d32 = dwc_read_reg32(&hcd->core_if->host_if->host_global_regs->hcfg);
+00153 
+00154         if (hcfg.b.perschedstat) {
+00155                 /* already enabled*/    
+00156                 return;
+00157         }
+00158         
+00159         dwc_write_reg32(&hcd->core_if->host_if->host_global_regs->hflbaddr, hcd->frame_list_dma);
+00160         
+00161         switch(fr_list_en) {
+00162         case 64:
+00163             hcfg.b.frlisten = 3;
+00164             break;
+00165         case 32:
+00166             hcfg.b.frlisten = 2;
+00167             break;
+00168         case 16:
+00169             hcfg.b.frlisten = 1;    
+00170         case 8:
+00171             hcfg.b.frlisten = 0;
+00172         default:
+00173             break;        
+00174         }
+00175         
+00176         hcfg.b.perschedena = 1;
+00177 
+00178         DWC_DEBUGPL(DBG_HCD, "Enabling Periodic schedule\n");
+00179         dwc_write_reg32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
+00180 
+00181 }
+00182  
+00183 static void per_sched_disable(dwc_otg_hcd_t * hcd)
+00184 {
+00185         hcfg_data_t hcfg;
+00186 
+00187         hcfg.d32 = dwc_read_reg32(&hcd->core_if->host_if->host_global_regs->hcfg);
+00188         
+00189         if (!hcfg.b.perschedstat) {
+00190                 /* already disabled */  
+00191                 return;
+00192         }
+00193         hcfg.b.perschedena = 0;
+00194         
+00195         DWC_DEBUGPL(DBG_HCD, "Disabling Periodic schedule\n");
+00196         dwc_write_reg32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32);
+00197 }
+00198 
+00199 /* 
+00200  * Activates/Deactivates FrameList entries for the channel 
+00201  * based on endpoint servicing period.
+00202  */
+00203 void update_frame_list(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t enable)
+00204 {
+00205         uint16_t i, j, inc;
+00206         dwc_hc_t *hc = qh->channel;
+00207         
+00208         inc = frame_incr_val(qh);
+00209         
+00210         if (qh->ep_type == UE_ISOCHRONOUS)
+00211                 i = frame_list_idx(qh->sched_frame);
+00212         else
+00213                 i = 0;
+00214 
+00215         j = i;
+00216         do {
+00217                 if (enable)
+00218                         hcd->frame_list[j] |= (1 << hc->hc_num);
+00219                 else
+00220                         hcd->frame_list[j] &= ~(1 << hc->hc_num);
+00221                 j = (j + inc) & (MAX_FRLIST_EN_NUM - 1);
+00222         }
+00223         while (j != i);
+00224         
+00225         if (!enable)
+00226                 return;
+00227         
+00228         hc->schinfo = 0;
+00229         if (qh->channel->speed == DWC_OTG_EP_SPEED_HIGH) {
+00230                 j = 1;
+00231                 for (i = 0 ; i < 8 / qh->interval; i++) {
+00232                         hc->schinfo |= j;
+00233                         j = j << qh->interval;
+00234                 }
+00235         }
+00236         else {
+00237                 hc->schinfo = 0xff;
+00238         }       
+00239 }               
+00240 #if 1
+00241 void dump_frame_list(dwc_otg_hcd_t * hcd)
+00242 {
+00243         int i = 0;
+00244         DWC_PRINTF("--FRAME LIST (hex) --\n");          
+00245         for (i = 0; i < MAX_FRLIST_EN_NUM; i++) {
+00246                 DWC_PRINTF("%x\t",hcd->frame_list[i]);
+00247                 if (!(i % 8) && i)    
+00248                         DWC_PRINTF("\n");
+00249         }
+00250         DWC_PRINTF("\n----\n");
+00251 
+00252 }
+00253 #endif
+00254 
+00255 static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+00256 {
+00257         dwc_hc_t *hc = qh->channel;
+00258         if (dwc_qh_is_non_per(qh)) {
+00259                 hcd->non_periodic_channels--;                   
+00260         }
+00261         else {
+00262                 update_frame_list(hcd, qh, 0);
+00263         }
+00264         /* 
+00265          * The condition is added to prevent double cleanup try in case of device
+00266          * disconnect. See channel cleanup in dwc_otg_hcd_disconnect_cb().
+00267          */
+00268         if (hc->qh) {   
+00269                 dwc_otg_hc_cleanup(hcd->core_if, hc);
+00270                 DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
+00271                 hc->qh = NULL;
+00272         }
+00273         
+00274         qh->channel = NULL;
+00275         qh->ntd = 0;
+00276         
+00277         if (qh->desc_list) {
+00278                 dwc_memset(qh->desc_list, 0x00, 
+00279                             sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
+00280         }
+00281 }
+00282 
+00294 int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+00295 {
+00296         int retval = 0;
+00297         
+00298         if (qh->do_split) {
+00299                 DWC_ERROR("SPLIT Transfers are not supported in Descriptor DMA.\n");
+00300                 return -1;
+00301         }
+00302 
+00303         retval = desc_list_alloc(qh);
+00304         
+00305         if ((retval == 0) && (qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)) {
+00306                 if(!hcd->frame_list) {
+00307                         retval = frame_list_alloc(hcd); 
+00308                         /* Enable periodic schedule on first periodic QH */
+00309                         if (retval == 0)                
+00310                                 per_sched_enable(hcd, MAX_FRLIST_EN_NUM);
+00311                 }
+00312         }
+00313         
+00314         qh->ntd = 0;
+00315         
+00316         return retval;
+00317 }
+00318 
+00327 void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+00328 {
+00329         desc_list_free(qh);
+00330 
+00331         /* 
+00332          * Channel still assigned due to some reasons. 
+00333          * Seen on Isoc URB dequeue. Channel halted but no subsequent
+00334          * ChHalted interrupt to release the channel. Afterwards
+00335          * when it comes here from endpoint disable routine
+00336          * channel remains assigned.
+00337          */
+00338         if (qh->channel)
+00339                 release_channel_ddma(hcd, qh);
+00340 
+00341         if ((qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT) 
+00342                         && !hcd->periodic_channels && hcd->frame_list) {
+00343                 
+00344                 per_sched_disable(hcd); 
+00345                 frame_list_free(hcd);   
+00346         }
+00347 }       
+00348 
+00349 static uint8_t frame_to_desc_idx(dwc_otg_qh_t * qh, uint16_t frame_idx)
+00350 {
+00351         if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
+00352                 /* 
+00353                  * Descriptor set(8 descriptors) index
+00354                  * which is 8-aligned.
+00355                  */     
+00356                 return (frame_idx & ((MAX_DMA_DESC_NUM_HS_ISOC / 8) - 1)) * 8;
+00357         }
+00358         else {
+00359                 return (frame_idx & (MAX_DMA_DESC_NUM_GENERIC - 1));
+00360         }       
+00361 }
+00362 
+00363 /* 
+00364  * Determine starting frame for Isochronous transfer. 
+00365  * Few frames skipped to prevent race condition with HC. 
+00366  */
+00367 static uint8_t calc_starting_frame(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t* skip_frames)
+00368 {
+00369         uint16_t frame = 0;
+00370         hcd->frame_number = dwc_otg_hcd_get_frame_number(hcd);
+00371         
+00372         /* sched_frame is always frame number(not uFrame) both in FS and HS !! */
+00373         
+00374         /* 
+00375          * skip_frames is used to limit activated descriptors number
+00376          * to avoid the situation when HC services the last activated
+00377          * descriptor firstly.
+00378          * Example for FS:
+00379          * Current frame is 1, scheduled frame is 3. Since HC always fetches the descriptor
+00380          * corresponding to curr_frame+1, the descriptor corresponding to frame 2
+00381          * will be fetched. If the number of descriptors is max=64 (or greather) the list will
+00382          * be fully programmed with Active descriptors and it is possible case(rare) that the latest 
+00383          * descriptor(considering rollback) corresponding to frame 2 will be serviced first.
+00384          * HS case is more probable because, in fact, up to 11 uframes(16 in the code)
+00385          * may be skipped.
+00386          */
+00387         if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) {
+00388                 /* 
+00389                  * Consider uframe counter also, to start xfer asap.
+00390                  * If half of the frame elapsed skip 2 frames otherwise
+00391                  * just 1 frame. 
+00392                  * Starting descriptor index must be 8-aligned, so
+00393                  * if the current frame is near to complete the next one
+00394                  * is skipped as well.
+00395                  */
+00396                         
+00397                 if (dwc_micro_frame_num(hcd->frame_number)  >= 5) {
+00398                         *skip_frames = 2 * 8;
+00399                         frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
+00400                 }       
+00401                 else {
+00402                         *skip_frames = 1 * 8;
+00403                         frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames);
+00404                 }       
+00405                                  
+00406                 frame = dwc_full_frame_num(frame); 
+00407         } else {
+00408                 /* 
+00409                  * Two frames are skipped for FS - the current and the next.
+00410                  * But for descriptor programming, 1 frame(descriptor) is enough,
+00411                  * see example above.
+00412                  */
+00413                 *skip_frames = 1;        
+00414                 frame = dwc_frame_num_inc(hcd->frame_number, 2);
+00415         }
+00416         
+00417         return frame;
+00418 }
+00419 /* 
+00420  * Calculate initial descriptor index for isochronous transfer
+00421  * based on scheduled frame. 
+00422  */
+00423 static uint8_t recalc_initial_desc_idx(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+00424 {
+00425         uint16_t frame = 0, fr_idx, fr_idx_tmp; 
+00426         uint8_t skip_frames = 0 ;
+00427         /* 
+00428          * With current ISOC processing algorithm the channel is being
+00429          * released when no more QTDs in the list(qh->ntd == 0).
+00430          * Thus this function is called only when qh->ntd == 0 and qh->channel == 0. 
+00431          *
+00432          * So qh->channel != NULL branch is not used and just not removed from the
+00433          * source file. It is required for another possible approach which is,
+00434          * do not disable and release the channel when ISOC session completed, 
+00435          * just move QH to inactive schedule until new QTD arrives. 
+00436          * On new QTD, the QH moved back to 'ready' schedule,
+00437          * starting frame and therefore starting desc_index are recalculated.
+00438          * In this case channel is released only on ep_disable.
+00439          */
+00440          
+00441         /* Calculate starting descriptor index. For INTERRUPT endpoint it is always 0. */
+00442         if (qh->channel) {
+00443                 frame = calc_starting_frame(hcd, qh, &skip_frames);     
+00444                 /* 
+00445                  * Calculate initial descriptor index based on FrameList current bitmap
+00446                  * and servicing period.
+00447                  */
+00448                 fr_idx_tmp = frame_list_idx(frame);
+00449                 fr_idx = (MAX_FRLIST_EN_NUM + frame_list_idx(qh->sched_frame) - fr_idx_tmp) 
+00450                                 % frame_incr_val(qh);
+00451                 fr_idx = (fr_idx + fr_idx_tmp) % MAX_FRLIST_EN_NUM;
+00452         }
+00453         else {
+00454                 qh->sched_frame = calc_starting_frame(hcd, qh, &skip_frames);   
+00455                 fr_idx = frame_list_idx(qh->sched_frame);
+00456         }
+00457         
+00458         qh->td_first = qh->td_last =  frame_to_desc_idx(qh, fr_idx);
+00459         
+00460         return skip_frames;
+00461 }
+00462  
+00463 #define ISOC_URB_GIVEBACK_ASAP
+00464  
+00465 #define MAX_ISOC_XFER_SIZE_FS 1023
+00466 #define MAX_ISOC_XFER_SIZE_HS 3072
+00467 #define DESCNUM_THRESHOLD 4
+00468 
+00469 static void init_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t skip_frames)
+00470 {
+00471         struct dwc_otg_hcd_iso_packet_desc *frame_desc;
+00472         dwc_otg_qtd_t *qtd;
+00473         dwc_otg_host_dma_desc_t *dma_desc;
+00474         uint16_t idx, inc, n_desc, ntd_max, max_xfer_size;
+00475         
+00476         idx = qh->td_last;
+00477         inc = qh->interval;
+00478         n_desc = 0;
+00479         
+00480         ntd_max = (max_desc_num(qh) + qh->interval - 1) / qh->interval;
+00481         if (skip_frames && !qh->channel)
+00482                 ntd_max = ntd_max - skip_frames / qh->interval; 
+00483         
+00484         max_xfer_size = (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) ? MAX_ISOC_XFER_SIZE_HS 
+00485                                                                  : MAX_ISOC_XFER_SIZE_FS;
+00486                         
+00487         DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
+00488                 while ((qh->ntd < ntd_max) && (qtd->isoc_frame_index_last < qtd->urb->packet_count)) {
+00489                                 
+00490                         dma_desc = &qh->desc_list[idx];
+00491                         dwc_memset(dma_desc, 0x00, sizeof(dwc_otg_host_dma_desc_t));
+00492 
+00493                         frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
+00494                         
+00495                         if (frame_desc->length > max_xfer_size)
+00496                                 qh->n_bytes[idx] = max_xfer_size;
+00497                         else
+00498                                 qh->n_bytes[idx] = frame_desc->length;
+00499                         dma_desc->status.b_isoc.n_bytes = qh->n_bytes[idx];
+00500                         dma_desc->status.b_isoc.a = 1;
+00501                         
+00502                         dma_desc->buf = qtd->urb->dma + frame_desc->offset;
+00503                         
+00504                         qh->ntd++;
+00505 
+00506                         qtd->isoc_frame_index_last++;
+00507                         
+00508                 #ifdef  ISOC_URB_GIVEBACK_ASAP
+00509                         /* 
+00510                          * Set IOC for each descriptor corresponding to the 
+00511                          * last frame of the URB.
+00512                          */     
+00513                         if (qtd->isoc_frame_index_last == qtd->urb->packet_count)
+00514                                 dma_desc->status.b_isoc.ioc = 1;
+00515                         
+00516                 #endif  
+00517                         idx = desclist_idx_inc(idx, inc, qh->dev_speed);
+00518                         n_desc++;
+00519                         
+00520                 }
+00521                 qtd->in_process = 1;
+00522         }
+00523         
+00524         qh->td_last = idx;
+00525         
+00526 #ifdef  ISOC_URB_GIVEBACK_ASAP
+00527         /* Set IOC for the last descriptor if descriptor list is full */        
+00528         if (qh->ntd == ntd_max) {
+00529                 idx = desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
+00530                 qh->desc_list[idx].status.b_isoc.ioc = 1;
+00531         }
+00532 #else   
+00533         /* 
+00534          * Set IOC bit only for one descriptor. 
+00535          * Always try to be ahead of HW processing,
+00536          * i.e. on IOC generation driver activates next descriptors but
+00537          * core continues to process descriptors followed the one with IOC set.
+00538          */
+00539 
+00540         if (n_desc > DESCNUM_THRESHOLD) {
+00541                 /* 
+00542                  * Move IOC "up". Required even if there is only one QTD 
+00543                  * in the list, cause QTDs migth continue to be queued,
+00544                  * but during the activation it was only one queued.
+00545                  * Actually more than one QTD might be in the list if this function called 
+00546                  * from XferCompletion - QTDs was queued during HW processing of the previous
+00547                  * descriptor chunk.
+00548                  */     
+00549                 idx = dwc_desclist_idx_dec(idx, inc * ((qh->ntd + 1) / 2), qh->dev_speed);
+00550         }
+00551         else {
+00552                 /* 
+00553                  * Set the IOC for the latest descriptor
+00554                  * if either number of descriptor is not greather than threshold
+00555                  * or no more new descriptors activated.
+00556                  */     
+00557                 idx = dwc_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
+00558         }
+00559         
+00560         qh->desc_list[idx].status.b_isoc.ioc = 1;
+00561 #endif
+00562 }
+00563 
+00564 
+00565 static void init_non_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+00566 {
+00567 
+00568         dwc_hc_t *hc;
+00569         dwc_otg_host_dma_desc_t *dma_desc;
+00570         dwc_otg_qtd_t *qtd;
+00571         int     num_packets, len, n_desc = 0;
+00572         
+00573         hc =  qh->channel;
+00574          
+00575         /* 
+00576          * Start with hc->xfer_buff initialized in 
+00577          * assign_and_init_hc(), then if SG transfer consists of multiple URBs,
+00578          * this pointer re-assigned to the buffer of the currently processed QTD.
+00579          * For non-SG request there is always one QTD active.
+00580          */
+00581         
+00582         DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) {
+00583                         
+00584                 if (n_desc) {
+00585                         /* SG request - more than 1 QTDs */
+00586                         hc->xfer_buff = (uint8_t *)qtd->urb->dma + qtd->urb->actual_length;
+00587                         hc->xfer_len = qtd->urb->length - qtd->urb->actual_length;
+00588                 }
+00589 
+00590                 qtd->n_desc = 0;
+00591                 
+00592                 do {
+00593                         dma_desc = &qh->desc_list[n_desc];
+00594                         len = hc->xfer_len;
+00595                         
+00596 
+00597                         if (len > MAX_DMA_DESC_SIZE)
+00598                                 len = MAX_DMA_DESC_SIZE - hc->max_packet + 1;
+00599                         
+00600                         if (hc->ep_is_in) {
+00601                                 if (len > 0) {
+00602                                         num_packets = (len + hc->max_packet - 1) / hc->max_packet;
+00603                                 }
+00604                                 else {
+00605                                         /* Need 1 packet for transfer length of 0. */
+00606                                         num_packets = 1;
+00607                                 }
+00608                                 /* Always program an integral # of max packets for IN transfers. */
+00609                                 len = num_packets * hc->max_packet;     
+00610                         }                               
+00611                                 
+00612                         dma_desc->status.b.n_bytes = len;
+00613                         
+00614                         qh->n_bytes[n_desc] = len;
+00615                         
+00616 
+00617                         if ((qh->ep_type == UE_CONTROL) && (qtd->control_phase == DWC_OTG_CONTROL_SETUP))
+00618                                 dma_desc->status.b.sup = 1; /* Setup Packet */
+00619                                 
+00620                         dma_desc->status.b.a = 1; /* Active descriptor */
+00621                         
+00622                         dma_desc->buf = (uint32_t) hc->xfer_buff;
+00623 
+00624                         /* 
+00625                          * Last descriptor(or single) of IN transfer 
+00626                          * with actual size less than MaxPacket.
+00627                          */
+00628                         if (len > hc->xfer_len) {
+00629                                 hc->xfer_len = 0;
+00630                         }
+00631                         else {
+00632                                 hc->xfer_buff += len;
+00633                                 hc->xfer_len -= len;
+00634                         }
+00635                         
+00636                         qtd->n_desc++;
+00637                         n_desc++;
+00638                 }
+00639                 while ((hc->xfer_len > 0) && (n_desc != MAX_DMA_DESC_NUM_GENERIC));
+00640                 
+00641 
+00642                 qtd->in_process = 1;
+00643                 
+00644                 if (n_desc == MAX_DMA_DESC_NUM_GENERIC)
+00645                         break;
+00646         }
+00647 
+00648         if (n_desc) {
+00649                 /* Request Transfer Complete interrupt for the last descriptor */
+00650                 qh->desc_list[n_desc-1].status.b.ioc = 1;
+00651                 /* End of List indicator */
+00652                 qh->desc_list[n_desc-1].status.b.eol = 1;
+00653                 
+00654                 hc->ntd = n_desc;
+00655         }
+00656 }
+00657 
+00675 void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+00676 {
+00677         /* Channel is already assigned */
+00678         dwc_hc_t *hc = qh->channel;
+00679         uint8_t skip_frames = 0;
+00680         
+00681         switch (hc->ep_type) {
+00682         case DWC_OTG_EP_TYPE_CONTROL:
+00683         case DWC_OTG_EP_TYPE_BULK:
+00684                 init_non_isoc_dma_desc(hcd, qh);
+00685                 
+00686                 dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
+00687                 break;
+00688         case DWC_OTG_EP_TYPE_INTR:
+00689                 init_non_isoc_dma_desc(hcd, qh);
+00690                 
+00691                 update_frame_list(hcd, qh, 1);
+00692                 
+00693                 dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
+00694                 break;
+00695         case DWC_OTG_EP_TYPE_ISOC:
+00696                         
+00697                 if(!qh->ntd)
+00698                         skip_frames = recalc_initial_desc_idx(hcd, qh);
+00699                 
+00700                 init_isoc_dma_desc(hcd, qh, skip_frames);
+00701 
+00702                 if (!hc->xfer_started) {
+00703 
+00704                         update_frame_list(hcd, qh, 1);
+00705                 
+00706                         /* 
+00707                          * Always set to max, instead of actual size.
+00708                          * Otherwise ntd will be changed with 
+00709                          * channel being enabled. Not recommended.
+00710                          *
+00711                          */     
+00712                         hc->ntd = max_desc_num(qh);
+00713                         /* Enable channel only once for ISOC */ 
+00714                         dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc);
+00715                 }
+00716                 
+00717                 break;
+00718         default:
+00719                 
+00720                 break;
+00721         }
+00722 }
+00723 
+00724 static void complete_isoc_xfer_ddma(dwc_otg_hcd_t *hcd,
+00725                                    dwc_hc_t *hc,
+00726                                    dwc_otg_hc_regs_t *hc_regs,
+00727                                    dwc_otg_halt_status_e halt_status)
+00728 {
+00729         struct dwc_otg_hcd_iso_packet_desc      *frame_desc;            
+00730         dwc_otg_qtd_t                           *qtd, *qtd_tmp;
+00731         dwc_otg_qh_t                            *qh;
+00732         dwc_otg_host_dma_desc_t                 *dma_desc;
+00733         uint16_t                                idx, remain;
+00734         uint8_t                                 urb_compl;      
+00735         
+00736         qh = hc->qh;
+00737         idx = qh->td_first;
+00738         
+00739 
+00740         if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
+00741                 DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry)
+00742                         qtd->in_process = 0;
+00743                 return; 
+00744         }
+00745         else if ((halt_status == DWC_OTG_HC_XFER_AHB_ERR) || 
+00746                         (halt_status == DWC_OTG_HC_XFER_BABBLE_ERR)) {
+00747                 /* 
+00748                  * Channel is halted in these error cases.
+00749                  * Considered as serious issues.
+00750                  * Complete all URBs marking all frames as failed, 
+00751                  * irrespective whether some of the descriptors(frames) succeeded or no.
+00752                  * Pass error code to completion routine as well, to
+00753                  * update urb->status, some of class drivers might use it to stop
+00754                  * queing transfer requests.
+00755                  */     
+00756                 int err = (halt_status == DWC_OTG_HC_XFER_AHB_ERR) 
+00757                                                         ? (-DWC_E_IO)
+00758                                                         : (-DWC_E_OVERFLOW);
+00759                                                 
+00760                 DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
+00761                         for(idx = 0; idx < qtd->urb->packet_count; idx++) {
+00762                                 frame_desc = &qtd->urb->iso_descs[idx];
+00763                                 frame_desc->status = err;
+00764                         }
+00765                         hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, err);
+00766                         dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
+00767                 }
+00768                 return; 
+00769         }
+00770         
+00771         
+00772         DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
+00773                 
+00774                 if (!qtd->in_process)
+00775                     break;
+00776                 
+00777                 urb_compl = 0;
+00778                 
+00779                 do {
+00780 
+00781                         dma_desc = &qh->desc_list[idx];
+00782                         
+00783                         frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
+00784                         remain = hc->ep_is_in ? dma_desc->status.b_isoc.n_bytes : 0;
+00785         
+00786                         if (dma_desc->status.b_isoc.sts == DMA_DESC_STS_PKTERR) {
+00787                                 /* 
+00788                                  * XactError or, unable to complete all the transactions 
+00789                                  * in the scheduled micro-frame/frame, 
+00790                                  * both indicated by DMA_DESC_STS_PKTERR.
+00791                                  */     
+00792                                 qtd->urb->error_count++;
+00793                                 frame_desc->actual_length = qh->n_bytes[idx] - remain;
+00794                                 frame_desc->status = -DWC_E_PROTOCOL;
+00795                         }
+00796                         else {
+00797                                 /* Success */   
+00798                                                                 
+00799                                 frame_desc->actual_length = qh->n_bytes[idx] - remain;
+00800                                 frame_desc->status = 0;
+00801                         }
+00802                         
+00803                         if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
+00804                                 /*
+00805                                  * urb->status is not used for isoc transfers here.
+00806                                  * The individual frame_desc status are used instead.
+00807                                  */
+00808 
+00809                                 hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
+00810                                 dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
+00811                                 
+00812                                 /* 
+00813                                  * This check is necessary because urb_dequeue can be called 
+00814                                  * from urb complete callback(sound driver example).
+00815                                  * All pending URBs are dequeued there, so no need for
+00816                                  * further processing.
+00817                                  */
+00818                                 if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {   
+00819                                         return;
+00820                                 }
+00821                                 
+00822                                 urb_compl = 1;          
+00823                                 
+00824                         }
+00825                         
+00826                         qh->ntd--;
+00827                         
+00828                         /* Stop if IOC requested descriptor reached */
+00829                         if (dma_desc->status.b_isoc.ioc) {
+00830                                 idx = desclist_idx_inc(idx, qh->interval, hc->speed);   
+00831                                 goto stop_scan;
+00832                         }
+00833                         
+00834                         idx = desclist_idx_inc(idx, qh->interval, hc->speed);
+00835                         
+00836                         if (urb_compl)
+00837                                 break;
+00838                 }
+00839                 while(idx != qh->td_first);
+00840         }
+00841 stop_scan:      
+00842         qh->td_first = idx;
+00843 }
+00844         
+00845 uint8_t update_non_isoc_urb_state_ddma(dwc_otg_hcd_t * hcd,
+00846                            dwc_hc_t * hc,
+00847                            dwc_otg_qtd_t * qtd,
+00848                            dwc_otg_host_dma_desc_t * dma_desc,
+00849                            dwc_otg_halt_status_e halt_status,
+00850                            uint32_t n_bytes,
+00851                            uint8_t *xfer_done)
+00852 {
+00853 
+00854         uint16_t remain = hc->ep_is_in ? dma_desc->status.b.n_bytes : 0;
+00855         dwc_otg_hcd_urb_t *urb = qtd->urb;
+00856         
+00857         
+00858         if (halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
+00859                 urb->status = -DWC_E_IO;
+00860                 return 1;
+00861         }
+00862         if (dma_desc->status.b.sts == DMA_DESC_STS_PKTERR) {
+00863                 switch (halt_status) {
+00864                 case DWC_OTG_HC_XFER_STALL:
+00865                         urb->status = -DWC_E_PIPE;
+00866                         break;
+00867                 case DWC_OTG_HC_XFER_BABBLE_ERR:
+00868                         urb->status = -DWC_E_OVERFLOW;
+00869                         break;
+00870                 case DWC_OTG_HC_XFER_XACT_ERR:
+00871                         urb->status = -DWC_E_PROTOCOL;
+00872                         break;
+00873                 default:        
+00874                         DWC_ERROR("%s: Unhandled descriptor error status (%d)\n", __func__,
+00875                                   halt_status);
+00876                         break;
+00877                 }
+00878                 return 1;
+00879         }
+00880         
+00881         if (dma_desc->status.b.a == 1) {
+00882                 DWC_DEBUGPL(DBG_HCDV, "Active descriptor encountered on channel %d\n", hc->hc_num);
+00883                 return 0;
+00884         }
+00885         
+00886         if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL) {
+00887             if (qtd->control_phase == DWC_OTG_CONTROL_DATA) {
+00888                 urb->actual_length += n_bytes - remain;
+00889                 if (remain || urb->actual_length == urb->length) {
+00890                         /* 
+00891                          * For Control Data stage do not set urb->status=0 to prevent
+00892                          * URB callback. Set it when Status phase done. See below.
+00893                          */
+00894                         *xfer_done = 1;
+00895                 }               
+00896             
+00897             }
+00898             else if (qtd->control_phase == DWC_OTG_CONTROL_STATUS) {
+00899                 urb->status = 0;
+00900                 *xfer_done = 1;
+00901             }
+00902             /* No handling for SETUP stage */
+00903 
+00904         }
+00905         else { 
+00906             /* BULK and INTR */
+00907             urb->actual_length += n_bytes - remain;
+00908             if (remain || urb->actual_length == urb->length) {
+00909                 urb->status = 0;
+00910                 *xfer_done = 1;
+00911             }
+00912         }
+00913 
+00914         return 0;
+00915 }
+00916 
+00917 static void complete_non_isoc_xfer_ddma(dwc_otg_hcd_t * hcd,
+00918                                         dwc_hc_t * hc,
+00919                                         dwc_otg_hc_regs_t * hc_regs,
+00920                                         dwc_otg_halt_status_e halt_status)
+00921 {
+00922         dwc_otg_hcd_urb_t       *urb = NULL;
+00923         dwc_otg_qtd_t           *qtd, *qtd_tmp;
+00924         dwc_otg_qh_t            *qh;
+00925         dwc_otg_host_dma_desc_t *dma_desc;
+00926         uint32_t                n_bytes, n_desc, i;
+00927         uint8_t                 failed = 0, xfer_done;
+00928         
+00929         n_desc = 0;
+00930         
+00931         qh = hc->qh;
+00932 
+00933         
+00934         if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
+00935                 DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) {
+00936                         qtd->in_process = 0;
+00937                 }
+00938                 return;
+00939         }
+00940         
+00941         DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
+00942                 
+00943                 urb = qtd->urb;
+00944 
+00945                 n_bytes = 0; 
+00946                 xfer_done = 0; 
+00947                 
+00948                 for (i = 0; i < qtd->n_desc; i++) {
+00949                         dma_desc = &qh->desc_list[n_desc];
+00950                 
+00951                         n_bytes = qh->n_bytes[n_desc];
+00952                         
+00953                         
+00954                         failed = update_non_isoc_urb_state_ddma(hcd, hc, qtd, dma_desc, 
+00955                                                                 halt_status, n_bytes, &xfer_done);
+00956                         
+00957                         if (failed || (xfer_done && (urb->status != -DWC_E_IN_PROGRESS))) {
+00958                                 
+00959                                 hcd->fops->complete(hcd, urb->priv, urb, urb->status);
+00960                                 dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
+00961 
+00962                                 if (failed)
+00963                                         goto stop_scan;
+00964                         }
+00965                         else if (qh->ep_type == UE_CONTROL) {
+00966                                 if (qtd->control_phase == DWC_OTG_CONTROL_SETUP) {
+00967                                         if (urb->length > 0) {
+00968                                                 qtd->control_phase = DWC_OTG_CONTROL_DATA;
+00969                                         } else {
+00970                                                 qtd->control_phase = DWC_OTG_CONTROL_STATUS;
+00971                                         }
+00972                                         DWC_DEBUGPL(DBG_HCDV, "  Control setup transaction done\n");
+00973                                 }
+00974                                 else if(qtd->control_phase == DWC_OTG_CONTROL_DATA) {
+00975                                         if (xfer_done) {
+00976                                                 qtd->control_phase = DWC_OTG_CONTROL_STATUS;
+00977                                                 DWC_DEBUGPL(DBG_HCDV, "  Control data transfer done\n");
+00978                                         } else if (i+1 == qtd->n_desc){
+00979                                                 /* 
+00980                                                  * Last descriptor for Control data stage which is
+00981                                                  * not completed yet.
+00982                                                  */     
+00983                                                 dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
+00984                                         }
+00985                                 }
+00986                         }
+00987                         
+00988                         n_desc++;
+00989                 }
+00990                 
+00991         }
+00992         
+00993 stop_scan:      
+00994         
+00995         if (qh->ep_type != UE_CONTROL) {
+00996                 /* 
+00997                  * Resetting the data toggle for bulk
+00998                  * and interrupt endpoints in case of stall. See handle_hc_stall_intr() 
+00999                  */     
+01000                 if (halt_status == DWC_OTG_HC_XFER_STALL) {     
+01001                         qh->data_toggle = DWC_OTG_HC_PID_DATA0; 
+01002                 }
+01003                 else {
+01004                         dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
+01005                 }
+01006         }
+01007         
+01008         if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
+01009                 hcint_data_t hcint;
+01010                 hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+01011                 if (hcint.b.nyet) {
+01012                         /*
+01013                          * Got a NYET on the last transaction of the transfer. It
+01014                          * means that the endpoint should be in the PING state at the
+01015                          * beginning of the next transfer.
+01016                          */
+01017                         qh->ping_state = 1;
+01018                         clear_hc_int(hc_regs, nyet);
+01019                 }
+01020 
+01021         }
+01022 
+01023 }
+01024 
+01042 void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t *hcd,
+01043                             dwc_hc_t *hc,
+01044                             dwc_otg_hc_regs_t *hc_regs,
+01045                             dwc_otg_halt_status_e halt_status)
+01046 {
+01047         uint8_t continue_isoc_xfer = 0;
+01048         dwc_otg_transaction_type_e tr_type;
+01049         dwc_otg_qh_t *qh = hc->qh;
+01050         
+01051         if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+01052 
+01053                 complete_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
+01054                 
+01055                 /* Release the channel if halted or session completed */        
+01056                 if (halt_status != DWC_OTG_HC_XFER_COMPLETE ||
+01057                                 DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
+01058 
+01059                         /* Halt the channel if session completed */     
+01060                         if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
+01061                                 dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
+01062                         }       
+01063                         
+01064                         release_channel_ddma(hcd, qh);
+01065                         dwc_otg_hcd_qh_remove(hcd, qh);
+01066                 }
+01067                 else {
+01068                         /* Keep in assigned schedule to continue transfer */
+01069                         DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
+01070                                            &qh->qh_list_entry);
+01071                         continue_isoc_xfer = 1;
+01072                                 
+01073                 }
+01077         }
+01078         else {
+01079                 /* Scan descriptor list to complete the URB(s), then release the channel */     
+01080                 complete_non_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status);
+01081                 
+01082                 release_channel_ddma(hcd, qh);
+01083                 
+01084                 dwc_otg_hcd_qh_remove(hcd, qh);
+01085                 
+01086                 if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
+01087                         /* Add back to inactive non-periodic schedule on normal completion */
+01088                         dwc_otg_hcd_qh_add(hcd, qh);
+01089                 }
+01090         
+01091 
+01092         }
+01093         tr_type = dwc_otg_hcd_select_transactions(hcd);
+01094         if (tr_type != DWC_OTG_TRANSACTION_NONE || continue_isoc_xfer) {
+01095                 if (continue_isoc_xfer) {
+01096                         if (tr_type == DWC_OTG_TRANSACTION_NONE) {
+01097                                 tr_type = DWC_OTG_TRANSACTION_PERIODIC;
+01098                         } else if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC) {
+01099                                 tr_type = DWC_OTG_TRANSACTION_ALL;
+01100                         }
+01101                 }
+01102                 dwc_otg_hcd_queue_transactions(hcd, tr_type);
+01103         }
+01104 }
+01105         
+01106 #endif  /* DWC_DEVICE_ONLY */
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__ddma_8c.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__ddma_8c.html new file mode 100644 index 000000000000..813b9526f3d9 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__ddma_8c.html @@ -0,0 +1,311 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hcd_ddma.c File Reference + + + + + + +

dwc_otg_hcd_ddma.c File Reference

This file contains Descriptor DMA support implementation for host mode. More... +

+#include "dwc_otg_hcd.h"
+#include "dwc_otg_regs.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Defines

+#define ISOC_URB_GIVEBACK_ASAP
+#define MAX_ISOC_XFER_SIZE_FS   1023
+#define MAX_ISOC_XFER_SIZE_HS   3072
+#define DESCNUM_THRESHOLD   4

Functions

+static uint8_t frame_list_idx (uint16_t frame)
+static uint16_t desclist_idx_inc (uint16_t idx, uint16_t inc, uint8_t speed)
+static uint16_t desclist_idx_dec (uint16_t idx, uint16_t inc, uint8_t speed)
+static uint16_t max_desc_num (dwc_otg_qh_t *qh)
+static uint16_t frame_incr_val (dwc_otg_qh_t *qh)
+static int desc_list_alloc (dwc_otg_qh_t *qh)
+static void desc_list_free (dwc_otg_qh_t *qh)
+static int frame_list_alloc (dwc_otg_hcd_t *hcd)
+static void frame_list_free (dwc_otg_hcd_t *hcd)
+static void per_sched_enable (dwc_otg_hcd_t *hcd, uint16_t fr_list_en)
+static void per_sched_disable (dwc_otg_hcd_t *hcd)
+void update_frame_list (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, uint8_t enable)
+void dump_frame_list (dwc_otg_hcd_t *hcd)
+static void release_channel_ddma (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
int dwc_otg_hcd_qh_init_ddma (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
 Initializes a QH structure's Descriptor DMA related members.
void dwc_otg_hcd_qh_free_ddma (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
 Frees descriptor list memory associated with the QH.
+static uint8_t frame_to_desc_idx (dwc_otg_qh_t *qh, uint16_t frame_idx)
+static uint8_t calc_starting_frame (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, uint8_t *skip_frames)
+static uint8_t recalc_initial_desc_idx (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
+static void init_isoc_dma_desc (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, uint8_t skip_frames)
+static void init_non_isoc_dma_desc (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
void dwc_otg_hcd_start_xfer_ddma (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
 For Control and Bulk endpoints initializes descriptor list and starts the transfer.
+static void complete_isoc_xfer_ddma (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_halt_status_e halt_status)
+uint8_t update_non_isoc_urb_state_ddma (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_qtd_t *qtd, dwc_otg_host_dma_desc_t *dma_desc, dwc_otg_halt_status_e halt_status, uint32_t n_bytes, uint8_t *xfer_done)
+static void complete_non_isoc_xfer_ddma (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_halt_status_e halt_status)
void dwc_otg_hcd_complete_xfer_ddma (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_halt_status_e halt_status)
 This function is called from interrupt handlers.
+


Detailed Description

+This file contains Descriptor DMA support implementation for host mode. +

+ +

+Definition in file dwc_otg_hcd_ddma.c.


Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_qh_init_ddma (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh 
)
+
+
+ +

+Initializes a QH structure's Descriptor DMA related members. +

+Allocates memory for descriptor list. On first periodic QH, allocates memory for FrameList and enables periodic scheduling.

+

Parameters:
+ + + +
hcd The HCD state structure for the DWC OTG controller.
qh The QH to init.
+
+
Returns:
0 if successful, negative error code otherwise.
+ +

+Definition at line 294 of file dwc_otg_hcd_ddma.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_qh_free_ddma (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh 
)
+
+
+ +

+Frees descriptor list memory associated with the QH. +

+If QH is periodic and the last, frees FrameList memory and disables periodic scheduling.

+

Parameters:
+ + + +
hcd The HCD state structure for the DWC OTG controller.
qh The QH to init.
+
+ +

+Definition at line 327 of file dwc_otg_hcd_ddma.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_start_xfer_ddma (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh 
)
+
+
+ +

+For Control and Bulk endpoints initializes descriptor list and starts the transfer. +

+For Interrupt and Isochronous endpoints initializes descriptor list then updates FrameList, marking appropriate entries as active. In case of Isochronous, the starting descriptor index is calculated based on the scheduled frame, but only on the first transfer descriptor within a session. Then starts the transfer via enabling the channel. For Isochronous endpoint the channel is not halted on XferComplete interrupt so remains assigned to the endpoint(QH) until session is done.

+

Parameters:
+ + + +
hcd The HCD state structure for the DWC OTG controller.
qh The QH to init.
+
+
Returns:
0 if successful, negative error code otherwise.
+ +

+Definition at line 675 of file dwc_otg_hcd_ddma.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_complete_xfer_ddma (dwc_otg_hcd_t hcd,
dwc_hc_t hc,
dwc_otg_hc_regs_t hc_regs,
dwc_otg_halt_status_e  halt_status 
)
+
+
+ +

+This function is called from interrupt handlers. +

+Scans the descriptor list, updates URB's status and calls completion routine for the URB if it's done. Releases the channel to be used by other transfers. In case of Isochronous endpoint the channel is not halted until the end of the session, i.e. QTD list is empty. If periodic channel released the FrameList is updated accordingly.

+Calls transaction selection routines to activate pending transfers.

+

Parameters:
+ + + + + +
hcd The HCD state structure for the DWC OTG controller.
hc Host channel, the transfer is completed on.
hc_regs Host channel registers.
halt_status Reason the channel is being halted, or just XferComplete for isochronous transfer
+
+ +

+

Todo:
Consider the case when period exceeds FrameList size. Frame Rollover interrupt should be used.
+ +

+Definition at line 1042 of file dwc_otg_hcd_ddma.c. +

+

+


Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__if_8h-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__if_8h-source.html new file mode 100644 index 000000000000..11bddbcc2f30 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__if_8h-source.html @@ -0,0 +1,191 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hcd_if.h Source File + + + + + + +

dwc_otg_hcd_if.h

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_if.h $
+00003  * $Revision: #6 $
+00004  * $Date: 2009/04/21 $
+00005  * $Change: 1237474 $
+00006  *
+00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009  * otherwise expressly agreed to in writing between Synopsys and you.
+00010  *
+00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012  * any End User Software License Agreement or Agreement for Licensed Product
+00013  * with Synopsys or any supplement thereto. You are permitted to use and
+00014  * redistribute this Software in source and binary forms, with or without
+00015  * modification, provided that redistributions of source code must retain this
+00016  * notice. You may not view, use, disclose, copy or distribute this file or
+00017  * any information contained herein except pursuant to this license grant from
+00018  * Synopsys. If you do not agree with this notice, including the disclaimer
+00019  * below, then you are not authorized to use the Software.
+00020  *
+00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031  * DAMAGE.
+00032  * ========================================================================== */
+00033 #ifndef DWC_DEVICE_ONLY
+00034 #ifndef __DWC_HCD_IF_H__
+00035 #define __DWC_HCD_IF_H__
+00036 
+00037 #include "dwc_otg_core_if.h"
+00038 
+00043 struct dwc_otg_hcd;
+00044 typedef struct dwc_otg_hcd dwc_otg_hcd_t;
+00045 
+00046 struct dwc_otg_hcd_urb;
+00047 typedef struct dwc_otg_hcd_urb dwc_otg_hcd_urb_t;
+00048 
+00053 typedef int (*dwc_otg_hcd_start_cb_t) (dwc_otg_hcd_t * hcd);
+00054 
+00056 typedef int (*dwc_otg_hcd_disconnect_cb_t) (dwc_otg_hcd_t * hcd);
+00057 
+00059 typedef int (*dwc_otg_hcd_hub_info_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
+00060                                                    void *urb_handle,
+00061                                                    uint32_t * hub_addr,
+00062                                                    uint32_t * port_addr);
+00064 typedef int (*dwc_otg_hcd_speed_from_urb_cb_t) (dwc_otg_hcd_t * hcd,
+00065                                                 void *urb_handle);
+00066 
+00068 typedef int (*dwc_otg_hcd_complete_urb_cb_t) (dwc_otg_hcd_t * hcd,
+00069                                               void *urb_handle,
+00070                                               dwc_otg_hcd_urb_t * dwc_otg_urb,
+00071                                               int32_t status);
+00072 
+00074 typedef int (*dwc_otg_hcd_get_b_hnp_enable) (dwc_otg_hcd_t * hcd);
+00075 
+00076 struct dwc_otg_hcd_function_ops {
+00077         dwc_otg_hcd_start_cb_t start;
+00078         dwc_otg_hcd_disconnect_cb_t disconnect;
+00079         dwc_otg_hcd_hub_info_from_urb_cb_t hub_info;
+00080         dwc_otg_hcd_speed_from_urb_cb_t speed;
+00081         dwc_otg_hcd_complete_urb_cb_t complete;
+00082         dwc_otg_hcd_get_b_hnp_enable get_b_hnp_enable;
+00083 };
+00089 extern dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void);
+00090 
+00099 extern int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if);
+00100 
+00105 extern void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd);
+00106 
+00114 extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
+00115 
+00122 extern void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd);
+00123 
+00130 extern void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data);
+00131 
+00141 extern int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd,
+00142                              struct dwc_otg_hcd_function_ops *fops);
+00143 
+00150 extern void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd);
+00151 
+00165 extern int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd,
+00166                                    uint16_t typeReq, uint16_t wValue,
+00167                                    uint16_t wIndex, uint8_t * buf,
+00168                                    uint16_t wLength);
+00169 
+00175 extern uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd);
+00176 
+00182 extern uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd);
+00183 
+00189 extern int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * hcd);
+00190 
+00196 extern void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd);
+00197 
+00206 extern void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd);
+00207 
+00219 extern int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr,
+00220                                 uint8_t hird, uint8_t bRemoteWake);
+00221 
+00222 /* URB interface */
+00223 
+00232 extern dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd,
+00233                                                 int iso_desc_count,
+00234                                                 int atomic_alloc);
+00235 
+00246 extern void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * hcd_urb,
+00247                                          uint8_t devaddr, uint8_t ep_num,
+00248                                          uint8_t ep_type, uint8_t ep_dir,
+00249                                          uint16_t mps);
+00250 
+00251 /* Transfer flags */ 
+00252 #define URB_GIVEBACK_ASAP 0x1
+00253 #define URB_SEND_ZERO_PACKET 0x2
+00254 
+00269 extern void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * urb,
+00270                                        void *urb_handle, void *buf,
+00271                                        dwc_dma_t dma, uint32_t buflen, void *sp,
+00272                                        dwc_dma_t sp_dma, uint32_t flags,
+00273                                        uint16_t interval);
+00274 
+00279 extern uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb);
+00280 
+00285 extern uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t *
+00286                                                   dwc_otg_urb);
+00287 
+00292 extern uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t *
+00293                                                 dwc_otg_urb);
+00294 
+00302 extern void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb,
+00303                                                 int desc_num, uint32_t offset,
+00304                                                 uint32_t length);
+00305 
+00311 extern uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t *
+00312                                                     dwc_otg_urb, int desc_num);
+00313 
+00319 extern uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t *
+00320                                                            dwc_otg_urb,
+00321                                                            int desc_num);
+00322 
+00333 extern int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * dwc_otg_hcd,
+00334                                    dwc_otg_hcd_urb_t * dwc_otg_urb,
+00335                                    void **ep_handle);
+00336 
+00342 extern int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * dwc_otg_hcd,
+00343                                    dwc_otg_hcd_urb_t * dwc_otg_urb);
+00344 
+00355 extern int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle,
+00356                                         int retry);
+00357 
+00363 extern int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port);
+00364 
+00371 extern int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd,
+00372                                               void *ep_handle);
+00373 
+00379 extern int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle);
+00380 
+00387 extern uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd,
+00388                                             void *ep_handle);
+00389 
+00392 #endif                          /* __DWC_HCD_IF_H__ */
+00393 #endif                          /* DWC_DEVICE_ONLY */
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__if_8h.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__if_8h.html new file mode 100644 index 000000000000..3bb51aa10f3e --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__if_8h.html @@ -0,0 +1,1381 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hcd_if.h File Reference + + + + + + +

dwc_otg_hcd_if.h File Reference

This file defines DWC_OTG HCD Core API. More... +

+#include "dwc_otg_core_if.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Structures

struct  dwc_otg_hcd_function_ops

HCD Core API

+#define URB_GIVEBACK_ASAP   0x1
+#define URB_SEND_ZERO_PACKET   0x2
+dwc_otg_hcd_tdwc_otg_hcd_alloc_hcd (void)
 This function allocates dwc_otg_hcd structure and returns pointer on it.
int dwc_otg_hcd_init (dwc_otg_hcd_t *hcd, dwc_otg_core_if_t *core_if)
 This function should be called to initiate HCD Core.
void dwc_otg_hcd_remove (dwc_otg_hcd_t *hcd)
 Frees HCD.
int32_t dwc_otg_hcd_handle_intr (dwc_otg_hcd_t *dwc_otg_hcd)
 This function should be called on every hardware interrupt.
void * dwc_otg_hcd_get_priv_data (dwc_otg_hcd_t *hcd)
 Returns private data set by dwc_otg_hcd_set_priv_data function.
void dwc_otg_hcd_set_priv_data (dwc_otg_hcd_t *hcd, void *priv_data)
 Set private data.
int dwc_otg_hcd_start (dwc_otg_hcd_t *hcd, struct dwc_otg_hcd_function_ops *fops)
 This function initializes the HCD Core.
void dwc_otg_hcd_stop (dwc_otg_hcd_t *hcd)
 Halts the DWC_otg host mode operations in a clean manner.
int dwc_otg_hcd_hub_control (dwc_otg_hcd_t *dwc_otg_hcd, uint16_t typeReq, uint16_t wValue, uint16_t wIndex, uint8_t *buf, uint16_t wLength)
 Handles hub class-specific requests.
uint32_t dwc_otg_hcd_otg_port (dwc_otg_hcd_t *hcd)
 Returns otg port number.
uint32_t dwc_otg_hcd_is_b_host (dwc_otg_hcd_t *hcd)
 Returns 1 if currently core is acting as B host, and 0 otherwise.
int dwc_otg_hcd_get_frame_number (dwc_otg_hcd_t *hcd)
 Returns current frame number.
void dwc_otg_hcd_dump_state (dwc_otg_hcd_t *hcd)
 Dumps hcd state.
void dwc_otg_hcd_dump_frrem (dwc_otg_hcd_t *hcd)
 Dump the average frame remaining at SOF.
int dwc_otg_hcd_send_lpm (dwc_otg_hcd_t *hcd, uint8_t devaddr, uint8_t hird, uint8_t bRemoteWake)
 Sends LPM transaction to the local device.
dwc_otg_hcd_urb_tdwc_otg_hcd_urb_alloc (dwc_otg_hcd_t *hcd, int iso_desc_count, int atomic_alloc)
 Allocates memory for dwc_otg_hcd_urb structure.
void dwc_otg_hcd_urb_set_pipeinfo (dwc_otg_hcd_urb_t *hcd_urb, uint8_t devaddr, uint8_t ep_num, uint8_t ep_type, uint8_t ep_dir, uint16_t mps)
 Set pipe information in URB.
void dwc_otg_hcd_urb_set_params (dwc_otg_hcd_urb_t *urb, void *urb_handle, void *buf, dwc_dma_t dma, uint32_t buflen, void *sp, dwc_dma_t sp_dma, uint32_t flags, uint16_t interval)
 Sets dwc_otg_hcd_urb parameters.
uint32_t dwc_otg_hcd_urb_get_status (dwc_otg_hcd_urb_t *dwc_otg_urb)
 Gets status from dwc_otg_hcd_urb.
uint32_t dwc_otg_hcd_urb_get_actual_length (dwc_otg_hcd_urb_t *dwc_otg_urb)
 Gets actual length from dwc_otg_hcd_urb.
uint32_t dwc_otg_hcd_urb_get_error_count (dwc_otg_hcd_urb_t *dwc_otg_urb)
 Gets error count from dwc_otg_hcd_urb.
void dwc_otg_hcd_urb_set_iso_desc_params (dwc_otg_hcd_urb_t *dwc_otg_urb, int desc_num, uint32_t offset, uint32_t length)
 Set ISOC descriptor offset and length.
uint32_t dwc_otg_hcd_urb_get_iso_desc_status (dwc_otg_hcd_urb_t *dwc_otg_urb, int desc_num)
 Get status of ISOC descriptor, specified by desc_num.
uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length (dwc_otg_hcd_urb_t *dwc_otg_urb, int desc_num)
 Get actual length of ISOC descriptor, specified by desc_num.
int dwc_otg_hcd_urb_enqueue (dwc_otg_hcd_t *dwc_otg_hcd, dwc_otg_hcd_urb_t *dwc_otg_urb, void **ep_handle)
 Queue URB.
int dwc_otg_hcd_urb_dequeue (dwc_otg_hcd_t *dwc_otg_hcd, dwc_otg_hcd_urb_t *dwc_otg_urb)
 De-queue the specified URB.
int dwc_otg_hcd_endpoint_disable (dwc_otg_hcd_t *hcd, void *ep_handle, int retry)
 Frees resources in the DWC_otg controller related to a given endpoint.
int dwc_otg_hcd_is_status_changed (dwc_otg_hcd_t *hcd, int port)
 Returns 1 if status of specified port is changed and 0 otherwise.
int dwc_otg_hcd_is_bandwidth_allocated (dwc_otg_hcd_t *hcd, void *ep_handle)
 Call this function to check if bandwidth was allocated for specified endpoint.
int dwc_otg_hcd_is_bandwidth_freed (dwc_otg_hcd_t *hcd, void *ep_handle)
 Call this function to check if bandwidth was freed for specified endpoint.
uint8_t dwc_otg_hcd_get_ep_bandwidth (dwc_otg_hcd_t *hcd, void *ep_handle)
 Returns bandwidth allocated for specified endpoint in microseconds.

HCD Function Driver Callbacks

+typedef int(*) dwc_otg_hcd_start_cb_t (dwc_otg_hcd_t *hcd)
 This function is called whenever core switches to host mode.
+typedef int(*) dwc_otg_hcd_disconnect_cb_t (dwc_otg_hcd_t *hcd)
 This function is called when device has been disconnected.
+typedef int(*) dwc_otg_hcd_hub_info_from_urb_cb_t (dwc_otg_hcd_t *hcd, void *urb_handle, uint32_t *hub_addr, uint32_t *port_addr)
 Wrapper provides this function to HCD to core, so it can get hub information to which device is connected.
+typedef int(*) dwc_otg_hcd_speed_from_urb_cb_t (dwc_otg_hcd_t *hcd, void *urb_handle)
 Via this function HCD core gets device speed.
+typedef int(*) dwc_otg_hcd_complete_urb_cb_t (dwc_otg_hcd_t *hcd, void *urb_handle, dwc_otg_hcd_urb_t *dwc_otg_urb, int32_t status)
 This function is called when urb is completed.
+typedef int(*) dwc_otg_hcd_get_b_hnp_enable (dwc_otg_hcd_t *hcd)
 Via this function HCD core gets b_hnp_enable parameter.

Typedefs

+typedef dwc_otg_hcd dwc_otg_hcd_t
+typedef dwc_otg_hcd_urb dwc_otg_hcd_urb_t
+


Detailed Description

+This file defines DWC_OTG HCD Core API. +

+ +

+Definition in file dwc_otg_hcd_if.h.


Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_init (dwc_otg_hcd_t hcd,
dwc_otg_core_if_t core_if 
)
+
+
+ +

+This function should be called to initiate HCD Core. +

+

Parameters:
+ + + +
hcd The HCD
core_if The DWC_OTG Core
+
+Returns -DWC_E_NO_MEMORY if no enough memory. Returns 0 on success +

+Definition at line 693 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_hcd_remove (dwc_otg_hcd_t hcd  ) 
+
+
+ +

+Frees HCD. +

+

Parameters:
+ + +
hcd The HCD
+
+ +

+Definition at line 778 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_hcd_handle_intr (dwc_otg_hcd_t dwc_otg_hcd  ) 
+
+
+ +

+This function should be called on every hardware interrupt. +

+

Parameters:
+ + +
dwc_otg_hcd The HCD
+
+Returns non zero if interrupt is handled Return 0 if interrupt is not handled +

+

Todo:
Implement i2cintr handler.
+ +

+Definition at line 43 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
void* dwc_otg_hcd_get_priv_data (dwc_otg_hcd_t hcd  ) 
+
+
+ +

+Returns private data set by dwc_otg_hcd_set_priv_data function. +

+

Parameters:
+ + +
hcd The HCD
+
+ +

+Definition at line 2671 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_set_priv_data (dwc_otg_hcd_t hcd,
void *  priv_data 
)
+
+
+ +

+Set private data. +

+

Parameters:
+ + + +
hcd The HCD
priv_data pointer to be stored in private data
+
+ +

+Definition at line 2676 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_start (dwc_otg_hcd_t hcd,
struct dwc_otg_hcd_function_ops fops 
)
+
+
+ +

+This function initializes the HCD Core. +

+

Parameters:
+ + + +
hcd The HCD
fops The Function Driver Operations data structure containing pointers to all callbacks.
+
+Returns -DWC_E_NO_DEVICE if Core is currently is in device mode. Returns 0 on success +

+Definition at line 2656 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_hcd_stop (dwc_otg_hcd_t hcd  ) 
+
+
+ +

+Halts the DWC_otg host mode operations in a clean manner. +

+USB transfers are stopped. +

+Definition at line 422 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_hub_control (dwc_otg_hcd_t dwc_otg_hcd,
uint16_t  typeReq,
uint16_t  wValue,
uint16_t  wIndex,
uint8_t *  buf,
uint16_t  wLength 
)
+
+
+ +

+Handles hub class-specific requests. +

+

Parameters:
+ + + + + + + +
dwc_otg_hcd The HCD
typeReq Request Type
wValue wValue from control request
wIndex wIndex from control request
buf data buffer
wLength data buffer length
+
+Returns -DWC_E_INVALID if invalid argument is passed Returns 0 on success +

+Definition at line 1905 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
uint32_t dwc_otg_hcd_otg_port (dwc_otg_hcd_t hcd  ) 
+
+
+ +

+Returns otg port number. +

+

Parameters:
+ + +
hcd The HCD
+
+ +

+Definition at line 2681 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
uint32_t dwc_otg_hcd_is_b_host (dwc_otg_hcd_t hcd  ) 
+
+
+ +

+Returns 1 if currently core is acting as B host, and 0 otherwise. +

+

Parameters:
+ + +
hcd The HCD
+
+ +

+Definition at line 2686 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
int dwc_otg_hcd_get_frame_number (dwc_otg_hcd_t hcd  ) 
+
+
+ +

+Returns current frame number. +

+

Parameters:
+ + +
hcd The HCD
+
+ +

+Definition at line 2643 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_hcd_dump_state (dwc_otg_hcd_t hcd  ) 
+
+
+ +

+Dumps hcd state. +

+

Parameters:
+ + +
hcd The HCD
+
+ +

+Definition at line 2815 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_hcd_dump_frrem (dwc_otg_hcd_t hcd  ) 
+
+
+ +

+Dump the average frame remaining at SOF. +

+This can be used to determine average interrupt latency. Frame remaining is also shown for start transfer and two additional sample points. Currently this function is not implemented.

+

Parameters:
+ + +
hcd The HCD
+
+ +

+Definition at line 2991 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_send_lpm (dwc_otg_hcd_t hcd,
uint8_t  devaddr,
uint8_t  hird,
uint8_t  bRemoteWake 
)
+
+
+ +

+Sends LPM transaction to the local device. +

+

Parameters:
+ + + + + +
hcd The HCD
devaddr Device Address
hird Host initiated resume duration
bRemoteWake Value of bRemoteWake field in LPM transaction
+
+Returns negative value if sending LPM transaction was not succeeded. Returns 0 on success. +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
dwc_otg_hcd_urb_t* dwc_otg_hcd_urb_alloc (dwc_otg_hcd_t hcd,
int  iso_desc_count,
int  atomic_alloc 
)
+
+
+ +

+Allocates memory for dwc_otg_hcd_urb structure. +

+Allocated memory should be freed by call dwc_free function.

+

Parameters:
+ + + + +
hcd The HCD
iso_desc_count Count of ISOC descriptors
atomic_alloc Specefies whether to perform atomic allocation.
+
+ +

+Definition at line 2698 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_urb_set_pipeinfo (dwc_otg_hcd_urb_t hcd_urb,
uint8_t  devaddr,
uint8_t  ep_num,
uint8_t  ep_type,
uint8_t  ep_dir,
uint16_t  mps 
)
+
+
+ +

+Set pipe information in URB. +

+

Parameters:
+ + + + + + + +
hcd_urb DWC_OTG URB
devaddr Device Address
ep_num Endpoint Number
ep_type Endpoint Type
ep_dir Endpoint Direction
mps Max Packet Size
+
+ +

+Definition at line 2717 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_urb_set_params (dwc_otg_hcd_urb_t urb,
void *  urb_handle,
void *  buf,
dwc_dma_t  dma,
uint32_t  buflen,
void *  sp,
dwc_dma_t  sp_dma,
uint32_t  flags,
uint16_t  interval 
)
+
+
+ +

+Sets dwc_otg_hcd_urb parameters. +

+

Parameters:
+ + + + + + + + + + +
urb DWC_OTG URB allocated by dwc_otg_hcd_urb_alloc function.
urb_handle Unique handle for request, this will be passed back to function driver in completion callback.
buf The buffer for the data
dma The DMA buffer for the data
buflen Transfer length
sp Buffer for setup data
sp_dma DMA address of setup data buffer
flags Transfer flags
interval Polling interval for interrupt or isochronous transfers.
+
+ +

+Definition at line 2730 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
uint32_t dwc_otg_hcd_urb_get_status (dwc_otg_hcd_urb_t dwc_otg_urb  ) 
+
+
+ +

+Gets status from dwc_otg_hcd_urb. +

+

Parameters:
+ + +
dwc_otg_urb DWC_OTG URB
+
+ +

+Definition at line 2747 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
uint32_t dwc_otg_hcd_urb_get_actual_length (dwc_otg_hcd_urb_t dwc_otg_urb  ) 
+
+
+ +

+Gets actual length from dwc_otg_hcd_urb. +

+

Parameters:
+ + +
dwc_otg_urb DWC_OTG URB
+
+ +

+Definition at line 2752 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + +
uint32_t dwc_otg_hcd_urb_get_error_count (dwc_otg_hcd_urb_t dwc_otg_urb  ) 
+
+
+ +

+Gets error count from dwc_otg_hcd_urb. +

+Only for ISOC URBs

+

Parameters:
+ + +
dwc_otg_urb DWC_OTG URB
+
+ +

+Definition at line 2757 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_urb_set_iso_desc_params (dwc_otg_hcd_urb_t dwc_otg_urb,
int  desc_num,
uint32_t  offset,
uint32_t  length 
)
+
+
+ +

+Set ISOC descriptor offset and length. +

+

Parameters:
+ + + + + +
dwc_otg_urb DWC_OTG URB
desc_num ISOC descriptor number
offset Offset from beginig of buffer.
length Transaction length
+
+ +

+Definition at line 2762 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
uint32_t dwc_otg_hcd_urb_get_iso_desc_status (dwc_otg_hcd_urb_t dwc_otg_urb,
int  desc_num 
)
+
+
+ +

+Get status of ISOC descriptor, specified by desc_num. +

+

Parameters:
+ + + +
dwc_otg_urb DWC_OTG URB
desc_num ISOC descriptor number
+
+ +

+Definition at line 2770 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length (dwc_otg_hcd_urb_t dwc_otg_urb,
int  desc_num 
)
+
+
+ +

+Get actual length of ISOC descriptor, specified by desc_num. +

+

Parameters:
+ + + +
dwc_otg_urb DWC_OTG URB
desc_num ISOC descriptor number
+
+ +

+Definition at line 2776 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_urb_enqueue (dwc_otg_hcd_t dwc_otg_hcd,
dwc_otg_hcd_urb_t dwc_otg_urb,
void **  ep_handle 
)
+
+
+ +

+Queue URB. +

+After transfer is completes, the complete callback will be called with the URB status

+

Parameters:
+ + + + +
dwc_otg_hcd The HCD
dwc_otg_urb DWC_OTG URB
ep_handle Out parameter for returning endpoint handle
+
+Returns -DWC_E_NO_DEVICE if no device is connected. Returns -DWC_E_NO_MEMORY if there is no enough memory. Returns 0 on success. +

+Definition at line 444 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_urb_dequeue (dwc_otg_hcd_t dwc_otg_hcd,
dwc_otg_hcd_urb_t dwc_otg_urb 
)
+
+
+ +

+De-queue the specified URB. +

+

Parameters:
+ + + +
dwc_otg_hcd The HCD
dwc_otg_urb DWC_OTG URB
+
+ +

+Definition at line 489 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_endpoint_disable (dwc_otg_hcd_t hcd,
void *  ep_handle,
int  retry 
)
+
+
+ +

+Frees resources in the DWC_otg controller related to a given endpoint. +

+Any URBs for the endpoint must already be dequeued.

+

Parameters:
+ + + + +
hcd The HCD
ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function
retry Number of retries if there are queued transfers.
+
+Returns -DWC_E_INVALID if invalid arguments are passed. Returns 0 on success +

+Definition at line 547 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_is_status_changed (dwc_otg_hcd_t hcd,
int  port 
)
+
+
+ +

+Returns 1 if status of specified port is changed and 0 otherwise. +

+

Parameters:
+ + + +
hcd The HCD
port Port number
+
+ +

+Definition at line 2611 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_is_bandwidth_allocated (dwc_otg_hcd_t hcd,
void *  ep_handle 
)
+
+
+ +

+Call this function to check if bandwidth was allocated for specified endpoint. +

+Only for ISOC and INTERRUPT endpoints.

+

Parameters:
+ + + +
hcd The HCD
ep_handle Endpoint handle
+
+ +

+Definition at line 2782 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_is_bandwidth_freed (dwc_otg_hcd_t hcd,
void *  ep_handle 
)
+
+
+ +

+Call this function to check if bandwidth was freed for specified endpoint. +

+

Parameters:
+ + + +
hcd The HCD
ep_handle Endpoint handle
+
+ +

+Definition at line 2795 of file dwc_otg_hcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
uint8_t dwc_otg_hcd_get_ep_bandwidth (dwc_otg_hcd_t hcd,
void *  ep_handle 
)
+
+
+ +

+Returns bandwidth allocated for specified endpoint in microseconds. +

+Only for ISOC and INTERRUPT endpoints.

+

Parameters:
+ + + +
hcd The HCD
ep_handle Endpoint handle
+
+ +

+Definition at line 2808 of file dwc_otg_hcd.c. +

+

+


Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__intr_8c-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__intr_8c-source.html new file mode 100644 index 000000000000..797ab8c44884 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__intr_8c-source.html @@ -0,0 +1,1873 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hcd_intr.c Source File + + + + + + +

dwc_otg_hcd_intr.c

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_intr.c $
+00003  * $Revision: #77 $
+00004  * $Date: 2009/04/21 $
+00005  * $Change: 1237475 $
+00006  *
+00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009  * otherwise expressly agreed to in writing between Synopsys and you.
+00010  *
+00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012  * any End User Software License Agreement or Agreement for Licensed Product
+00013  * with Synopsys or any supplement thereto. You are permitted to use and
+00014  * redistribute this Software in source and binary forms, with or without
+00015  * modification, provided that redistributions of source code must retain this
+00016  * notice. You may not view, use, disclose, copy or distribute this file or
+00017  * any information contained herein except pursuant to this license grant from
+00018  * Synopsys. If you do not agree with this notice, including the disclaimer
+00019  * below, then you are not authorized to use the Software.
+00020  *
+00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031  * DAMAGE.
+00032  * ========================================================================== */
+00033 #ifndef DWC_DEVICE_ONLY
+00034 
+00035 #include "dwc_otg_hcd.h"
+00036 #include "dwc_otg_regs.h"
+00037 
+00043 int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd)
+00044 {
+00045         int retval = 0;
+00046 
+00047         dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
+00048         gintsts_data_t gintsts;
+00049 #ifdef DEBUG
+00050         dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+00051 #endif
+00052 
+00053         /* Check if HOST Mode */
+00054         if (dwc_otg_is_host_mode(core_if)) {
+00055                 gintsts.d32 = dwc_otg_read_core_intr(core_if);
+00056                 if (!gintsts.d32) {
+00057                         return 0;
+00058                 }
+00059 #ifdef DEBUG
+00060                 /* Don't print debug message in the interrupt handler on SOF */
+00061 #ifndef DEBUG_SOF
+00062                 if (gintsts.d32 != DWC_SOF_INTR_MASK)
+00063 #endif
+00064                         DWC_DEBUGPL(DBG_HCD, "\n");
+00065 #endif
+00066 
+00067 #ifdef DEBUG
+00068 #ifndef DEBUG_SOF
+00069                 if (gintsts.d32 != DWC_SOF_INTR_MASK)
+00070 #endif
+00071                         DWC_DEBUGPL(DBG_HCD,
+00072                                     "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x\n",
+00073                                     gintsts.d32);
+00074 #endif
+00075 
+00076                 if (gintsts.b.sofintr) {
+00077                         retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd);
+00078                 }
+00079                 if (gintsts.b.rxstsqlvl) {
+00080                         retval |=
+00081                             dwc_otg_hcd_handle_rx_status_q_level_intr
+00082                             (dwc_otg_hcd);
+00083                 }
+00084                 if (gintsts.b.nptxfempty) {
+00085                         retval |=
+00086                             dwc_otg_hcd_handle_np_tx_fifo_empty_intr
+00087                             (dwc_otg_hcd);
+00088                 }
+00089                 if (gintsts.b.i2cintr) {
+00091                 }
+00092                 if (gintsts.b.portintr) {
+00093                         retval |= dwc_otg_hcd_handle_port_intr(dwc_otg_hcd);
+00094                 }
+00095                 if (gintsts.b.hcintr) {
+00096                         retval |= dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd);
+00097                 }
+00098                 if (gintsts.b.ptxfempty) {
+00099                         retval |=
+00100                             dwc_otg_hcd_handle_perio_tx_fifo_empty_intr
+00101                             (dwc_otg_hcd);
+00102                 }
+00103 #ifdef DEBUG
+00104 #ifndef DEBUG_SOF
+00105                 if (gintsts.d32 != DWC_SOF_INTR_MASK)
+00106 #endif
+00107                 {
+00108                         DWC_DEBUGPL(DBG_HCD,
+00109                                     "DWC OTG HCD Finished Servicing Interrupts\n");
+00110                         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintsts=0x%08x\n",
+00111                                     dwc_read_reg32(&global_regs->gintsts));
+00112                         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintmsk=0x%08x\n",
+00113                                     dwc_read_reg32(&global_regs->gintmsk));
+00114                 }
+00115 #endif
+00116 
+00117 #ifdef DEBUG
+00118 #ifndef DEBUG_SOF
+00119                 if (gintsts.d32 != DWC_SOF_INTR_MASK)
+00120 #endif
+00121                         DWC_DEBUGPL(DBG_HCD, "\n");
+00122 #endif
+00123 
+00124         }
+00125 
+00126         return retval;
+00127 }
+00128 
+00129 #ifdef DWC_TRACK_MISSED_SOFS
+00130 #warning Compiling code to track missed SOFs
+00131 #define FRAME_NUM_ARRAY_SIZE 1000
+00132 
+00135 static inline void track_missed_sofs(uint16_t curr_frame_number)
+00136 {
+00137         static uint16_t frame_num_array[FRAME_NUM_ARRAY_SIZE];
+00138         static uint16_t last_frame_num_array[FRAME_NUM_ARRAY_SIZE];
+00139         static int frame_num_idx = 0;
+00140         static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM;
+00141         static int dumped_frame_num_array = 0;
+00142 
+00143         if (frame_num_idx < FRAME_NUM_ARRAY_SIZE) {
+00144                 if (((last_frame_num + 1) & DWC_HFNUM_MAX_FRNUM) !=
+00145                     curr_frame_number) {
+00146                         frame_num_array[frame_num_idx] = curr_frame_number;
+00147                         last_frame_num_array[frame_num_idx++] = last_frame_num;
+00148                 }
+00149         } else if (!dumped_frame_num_array) {
+00150                 int i;
+00151                 DWC_PRINTF("Frame     Last Frame\n");
+00152                 DWC_PRINTF("-----     ----------\n");
+00153                 for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) {
+00154                         DWC_PRINTF("0x%04x    0x%04x\n",
+00155                                    frame_num_array[i], last_frame_num_array[i]);
+00156                 }
+00157                 dumped_frame_num_array = 1;
+00158         }
+00159         last_frame_num = curr_frame_number;
+00160 }
+00161 #endif
+00162 
+00169 int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd)
+00170 {
+00171         hfnum_data_t hfnum;
+00172         dwc_list_link_t *qh_entry;
+00173         dwc_otg_qh_t *qh;
+00174         dwc_otg_transaction_type_e tr_type;
+00175         gintsts_data_t gintsts = {.d32 = 0 };
+00176 
+00177         hfnum.d32 =
+00178             dwc_read_reg32(&hcd->core_if->host_if->host_global_regs->hfnum);
+00179 
+00180 #ifdef DEBUG_SOF
+00181         DWC_DEBUGPL(DBG_HCD, "--Start of Frame Interrupt--\n");
+00182 #endif
+00183         hcd->frame_number = hfnum.b.frnum;
+00184 
+00185 #ifdef DEBUG
+00186         hcd->frrem_accum += hfnum.b.frrem;
+00187         hcd->frrem_samples++;
+00188 #endif
+00189 
+00190 #ifdef DWC_TRACK_MISSED_SOFS
+00191         track_missed_sofs(hcd->frame_number);
+00192 #endif
+00193         /* Determine whether any periodic QHs should be executed. */
+00194         qh_entry = DWC_LIST_FIRST(&hcd->periodic_sched_inactive);
+00195         while (qh_entry != &hcd->periodic_sched_inactive) {
+00196                 qh = DWC_LIST_ENTRY(qh_entry, dwc_otg_qh_t, qh_list_entry);
+00197                 qh_entry = qh_entry->next;
+00198                 if (dwc_frame_num_le(qh->sched_frame, hcd->frame_number)) {
+00199                         /*
+00200                          * Move QH to the ready list to be executed next
+00201                          * (micro)frame.
+00202                          */
+00203                         DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
+00204                                            &qh->qh_list_entry);
+00205                 }
+00206         }
+00207         tr_type = dwc_otg_hcd_select_transactions(hcd);
+00208         if (tr_type != DWC_OTG_TRANSACTION_NONE) {
+00209                 dwc_otg_hcd_queue_transactions(hcd, tr_type);
+00210         }
+00211 
+00212         /* Clear interrupt */
+00213         gintsts.b.sofintr = 1;
+00214         dwc_write_reg32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32);
+00215 
+00216         return 1;
+00217 }
+00218 
+00222 int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t * dwc_otg_hcd)
+00223 {
+00224         host_grxsts_data_t grxsts;
+00225         dwc_hc_t *hc = NULL;
+00226 
+00227         DWC_DEBUGPL(DBG_HCD, "--RxStsQ Level Interrupt--\n");
+00228 
+00229         grxsts.d32 =
+00230             dwc_read_reg32(&dwc_otg_hcd->core_if->core_global_regs->grxstsp);
+00231 
+00232         hc = dwc_otg_hcd->hc_ptr_array[grxsts.b.chnum];
+00233 
+00234         /* Packet Status */
+00235         DWC_DEBUGPL(DBG_HCDV, "    Ch num = %d\n", grxsts.b.chnum);
+00236         DWC_DEBUGPL(DBG_HCDV, "    Count = %d\n", grxsts.b.bcnt);
+00237         DWC_DEBUGPL(DBG_HCDV, "    DPID = %d, hc.dpid = %d\n", grxsts.b.dpid,
+00238                     hc->data_pid_start);
+00239         DWC_DEBUGPL(DBG_HCDV, "    PStatus = %d\n", grxsts.b.pktsts);
+00240 
+00241         switch (grxsts.b.pktsts) {
+00242         case DWC_GRXSTS_PKTSTS_IN:
+00243                 /* Read the data into the host buffer. */
+00244                 if (grxsts.b.bcnt > 0) {
+00245                         dwc_otg_read_packet(dwc_otg_hcd->core_if,
+00246                                             hc->xfer_buff, grxsts.b.bcnt);
+00247 
+00248                         /* Update the HC fields for the next packet received. */
+00249                         hc->xfer_count += grxsts.b.bcnt;
+00250                         hc->xfer_buff += grxsts.b.bcnt;
+00251                 }
+00252 
+00253         case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
+00254         case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
+00255         case DWC_GRXSTS_PKTSTS_CH_HALTED:
+00256                 /* Handled in interrupt, just ignore data */
+00257                 break;
+00258         default:
+00259                 DWC_ERROR("RX_STS_Q Interrupt: Unknown status %d\n",
+00260                           grxsts.b.pktsts);
+00261                 break;
+00262         }
+00263 
+00264         return 1;
+00265 }
+00266 
+00271 int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd)
+00272 {
+00273         DWC_DEBUGPL(DBG_HCD, "--Non-Periodic TxFIFO Empty Interrupt--\n");
+00274         dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
+00275                                        DWC_OTG_TRANSACTION_NON_PERIODIC);
+00276         return 1;
+00277 }
+00278 
+00283 int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd)
+00284 {
+00285         DWC_DEBUGPL(DBG_HCD, "--Periodic TxFIFO Empty Interrupt--\n");
+00286         dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
+00287                                        DWC_OTG_TRANSACTION_PERIODIC);
+00288         return 1;
+00289 }
+00290 
+00294 int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd)
+00295 {
+00296         int retval = 0;
+00297         hprt0_data_t hprt0;
+00298         hprt0_data_t hprt0_modify;
+00299 
+00300         hprt0.d32 = dwc_read_reg32(dwc_otg_hcd->core_if->host_if->hprt0);
+00301         hprt0_modify.d32 = dwc_read_reg32(dwc_otg_hcd->core_if->host_if->hprt0);
+00302 
+00303         /* Clear appropriate bits in HPRT0 to clear the interrupt bit in
+00304          * GINTSTS */
+00305 
+00306         hprt0_modify.b.prtena = 0;
+00307         hprt0_modify.b.prtconndet = 0;
+00308         hprt0_modify.b.prtenchng = 0;
+00309         hprt0_modify.b.prtovrcurrchng = 0;
+00310 
+00311         /* Port Connect Detected
+00312          * Set flag and clear if detected */
+00313         if (hprt0.b.prtconndet) {
+00314                 DWC_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x "
+00315                             "Port Connect Detected--\n", hprt0.d32);
+00316                 dwc_otg_hcd->flags.b.port_connect_status_change = 1;
+00317                 dwc_otg_hcd->flags.b.port_connect_status = 1;
+00318                 hprt0_modify.b.prtconndet = 1;
+00319 
+00320                 /* B-Device has connected, Delete the connection timer. */
+00321                 DWC_TIMER_CANCEL(dwc_otg_hcd->conn_timer);
+00322 
+00323                 /* The Hub driver asserts a reset when it sees port connect
+00324                  * status change flag */
+00325                 retval |= 1;
+00326         }
+00327 
+00328         /* Port Enable Changed
+00329          * Clear if detected - Set internal flag if disabled */
+00330         if (hprt0.b.prtenchng) {
+00331                 DWC_DEBUGPL(DBG_HCD, "  --Port Interrupt HPRT0=0x%08x "
+00332                             "Port Enable Changed--\n", hprt0.d32);
+00333                 hprt0_modify.b.prtenchng = 1;
+00334                 if (hprt0.b.prtena == 1) {
+00335                         int do_reset = 0;
+00336                         dwc_otg_core_params_t *params =
+00337                             dwc_otg_hcd->core_if->core_params;
+00338                         dwc_otg_core_global_regs_t *global_regs =
+00339                             dwc_otg_hcd->core_if->core_global_regs;
+00340                         dwc_otg_host_if_t *host_if =
+00341                             dwc_otg_hcd->core_if->host_if;
+00342 
+00343                         /* Check if we need to adjust the PHY clock speed for
+00344                          * low power and adjust it */
+00345                         if (params->host_support_fs_ls_low_power) {
+00346                                 gusbcfg_data_t usbcfg;
+00347 
+00348                                 usbcfg.d32 =
+00349                                     dwc_read_reg32(&global_regs->gusbcfg);
+00350 
+00351                                 if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED
+00352                                     || hprt0.b.prtspd ==
+00353                                     DWC_HPRT0_PRTSPD_FULL_SPEED) {
+00354                                         /*
+00355                                          * Low power
+00356                                          */
+00357                                         hcfg_data_t hcfg;
+00358                                         if (usbcfg.b.phylpwrclksel == 0) {
+00359                                                 /* Set PHY low power clock select for FS/LS devices */
+00360                                                 usbcfg.b.phylpwrclksel = 1;
+00361                                                 dwc_write_reg32(&global_regs->
+00362                                                                 gusbcfg,
+00363                                                                 usbcfg.d32);
+00364                                                 do_reset = 1;
+00365                                         }
+00366 
+00367                                         hcfg.d32 =
+00368                                             dwc_read_reg32(&host_if->
+00369                                                            host_global_regs->hcfg);
+00370 
+00371                                         if (hprt0.b.prtspd ==
+00372                                             DWC_HPRT0_PRTSPD_LOW_SPEED
+00373                                             && params->
+00374                                             host_ls_low_power_phy_clk ==
+00375                                             DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ)
+00376                                         {
+00377                                                 /* 6 MHZ */
+00378                                                 DWC_DEBUGPL(DBG_CIL,
+00379                                                             "FS_PHY programming HCFG to 6 MHz (Low Power)\n");
+00380                                                 if (hcfg.b.fslspclksel !=
+00381                                                     DWC_HCFG_6_MHZ) {
+00382                                                         hcfg.b.fslspclksel =
+00383                                                             DWC_HCFG_6_MHZ;
+00384                                                         dwc_write_reg32
+00385                                                             (&host_if->
+00386                                                              host_global_regs->
+00387                                                              hcfg, hcfg.d32);
+00388                                                         do_reset = 1;
+00389                                                 }
+00390                                         } else {
+00391                                                 /* 48 MHZ */
+00392                                                 DWC_DEBUGPL(DBG_CIL,
+00393                                                             "FS_PHY programming HCFG to 48 MHz ()\n");
+00394                                                 if (hcfg.b.fslspclksel !=
+00395                                                     DWC_HCFG_48_MHZ) {
+00396                                                         hcfg.b.fslspclksel =
+00397                                                             DWC_HCFG_48_MHZ;
+00398                                                         dwc_write_reg32
+00399                                                             (&host_if->
+00400                                                              host_global_regs->
+00401                                                              hcfg, hcfg.d32);
+00402                                                         do_reset = 1;
+00403                                                 }
+00404                                         }
+00405                                 } else {
+00406                                         /*
+00407                                          * Not low power
+00408                                          */
+00409                                         if (usbcfg.b.phylpwrclksel == 1) {
+00410                                                 usbcfg.b.phylpwrclksel = 0;
+00411                                                 dwc_write_reg32(&global_regs->
+00412                                                                 gusbcfg,
+00413                                                                 usbcfg.d32);
+00414                                                 do_reset = 1;
+00415                                         }
+00416                                 }
+00417 
+00418                                 if (do_reset) {
+00419                                         DWC_TASK_SCHEDULE(dwc_otg_hcd->
+00420                                                           reset_tasklet);
+00421                                 }
+00422                         }
+00423 
+00424                         if (!do_reset) {
+00425                                 /* Port has been enabled set the reset change flag */
+00426                                 dwc_otg_hcd->flags.b.port_reset_change = 1;
+00427                         }
+00428                 } else {
+00429                         dwc_otg_hcd->flags.b.port_enable_change = 1;
+00430                 }
+00431                 retval |= 1;
+00432         }
+00433 
+00435         if (hprt0.b.prtovrcurrchng) {
+00436                 DWC_DEBUGPL(DBG_HCD, "  --Port Interrupt HPRT0=0x%08x "
+00437                             "Port Overcurrent Changed--\n", hprt0.d32);
+00438                 dwc_otg_hcd->flags.b.port_over_current_change = 1;
+00439                 hprt0_modify.b.prtovrcurrchng = 1;
+00440                 retval |= 1;
+00441         }
+00442 
+00443         /* Clear Port Interrupts */
+00444         dwc_write_reg32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32);
+00445 
+00446         return retval;
+00447 }
+00448 
+00453 int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd)
+00454 {
+00455         int i;
+00456         int retval = 0;
+00457         haint_data_t haint;
+00458 
+00459         /* Clear appropriate bits in HCINTn to clear the interrupt bit in
+00460          * GINTSTS */
+00461 
+00462         haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if);
+00463 
+00464         for (i = 0; i < dwc_otg_hcd->core_if->core_params->host_channels; i++) {
+00465                 if (haint.b2.chint & (1 << i)) {
+00466                         retval |= dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd, i);
+00467                 }
+00468         }
+00469 
+00470         return retval;
+00471 }
+00472 
+00473 
+00474 
+00485 static uint32_t get_actual_xfer_length(dwc_hc_t * hc,
+00486                                        dwc_otg_hc_regs_t * hc_regs,
+00487                                        dwc_otg_qtd_t * qtd,
+00488                                        dwc_otg_halt_status_e halt_status,
+00489                                        int *short_read)
+00490 {
+00491         hctsiz_data_t hctsiz;
+00492         uint32_t length;
+00493 
+00494         if (short_read != NULL) {
+00495                 *short_read = 0;
+00496         }
+00497         hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
+00498 
+00499         if (halt_status == DWC_OTG_HC_XFER_COMPLETE) {
+00500                 if (hc->ep_is_in) {
+00501                         length = hc->xfer_len - hctsiz.b.xfersize;
+00502                         if (short_read != NULL) {
+00503                                 *short_read = (hctsiz.b.xfersize != 0);
+00504                         }
+00505                 } else if (hc->qh->do_split) {
+00506                         length = qtd->ssplit_out_xfer_count;
+00507                 } else {
+00508                         length = hc->xfer_len;
+00509                 }
+00510         } else {
+00511                 /*
+00512                  * Must use the hctsiz.pktcnt field to determine how much data
+00513                  * has been transferred. This field reflects the number of
+00514                  * packets that have been transferred via the USB. This is
+00515                  * always an integral number of packets if the transfer was
+00516                  * halted before its normal completion. (Can't use the
+00517                  * hctsiz.xfersize field because that reflects the number of
+00518                  * bytes transferred via the AHB, not the USB).
+00519                  */
+00520                 length =
+00521                     (hc->start_pkt_count - hctsiz.b.pktcnt) * hc->max_packet;
+00522         }
+00523 
+00524         return length;
+00525 }
+00526 
+00536 static int update_urb_state_xfer_comp(dwc_hc_t * hc,
+00537                                       dwc_otg_hc_regs_t * hc_regs,
+00538                                       dwc_otg_hcd_urb_t * urb,
+00539                                       dwc_otg_qtd_t * qtd)
+00540 {
+00541         int xfer_done = 0;
+00542         int short_read = 0;
+00543 
+00544         int xfer_length;
+00545 
+00546         xfer_length = get_actual_xfer_length(hc, hc_regs, qtd,                                               
+00547                                                      DWC_OTG_HC_XFER_COMPLETE,
+00548                                                      &short_read);
+00549 
+00550 
+00551         /* non DWORD-aligned buffer case handling. */
+00552         if (hc->align_buff && xfer_length && hc->ep_is_in) {
+00553                 dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf, xfer_length);
+00554         }
+00555 
+00556         urb->actual_length += xfer_length;
+00557 
+00558         if(xfer_length && (hc->ep_type == DWC_OTG_EP_TYPE_BULK) &&
+00559            (urb->flags & URB_SEND_ZERO_PACKET) && (urb->actual_length == urb->length) &&
+00560            !(urb->length % hc->max_packet)) {
+00561                 xfer_done = 0;
+00562         } else if (short_read || urb->actual_length == urb->length) {
+00563                 xfer_done = 1;
+00564                 urb->status = 0;
+00565         }
+00566         
+00567 #ifdef DEBUG
+00568         {
+00569                 hctsiz_data_t hctsiz;
+00570                 hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
+00571                 DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
+00572                             __func__, (hc->ep_is_in ? "IN" : "OUT"),
+00573                             hc->hc_num);
+00574                 DWC_DEBUGPL(DBG_HCDV, "  hc->xfer_len %d\n", hc->xfer_len);
+00575                 DWC_DEBUGPL(DBG_HCDV, "  hctsiz.xfersize %d\n",
+00576                             hctsiz.b.xfersize);
+00577                 DWC_DEBUGPL(DBG_HCDV, "  urb->transfer_buffer_length %d\n",
+00578                             urb->length);
+00579                 DWC_DEBUGPL(DBG_HCDV, "  urb->actual_length %d\n",
+00580                             urb->actual_length);
+00581                 DWC_DEBUGPL(DBG_HCDV, "  short_read %d, xfer_done %d\n",
+00582                             short_read, xfer_done);
+00583         }
+00584 #endif
+00585 
+00586         return xfer_done;
+00587 }
+00588 
+00589 /*
+00590  * Save the starting data toggle for the next transfer. The data toggle is
+00591  * saved in the QH for non-control transfers and it's saved in the QTD for
+00592  * control transfers.
+00593  */
+00594 void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
+00595                              dwc_otg_hc_regs_t * hc_regs, dwc_otg_qtd_t * qtd)
+00596 {
+00597         hctsiz_data_t hctsiz;
+00598         hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
+00599 
+00600         if (hc->ep_type != DWC_OTG_EP_TYPE_CONTROL) {
+00601                 dwc_otg_qh_t *qh = hc->qh;
+00602                 if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
+00603                         qh->data_toggle = DWC_OTG_HC_PID_DATA0;
+00604                 } else {
+00605                         qh->data_toggle = DWC_OTG_HC_PID_DATA1;
+00606                 }
+00607         } else {
+00608                 if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) {
+00609                         qtd->data_toggle = DWC_OTG_HC_PID_DATA0;
+00610                 } else {
+00611                         qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
+00612                 }
+00613         }
+00614 }
+00615 
+00625 static dwc_otg_halt_status_e
+00626 update_isoc_urb_state(dwc_otg_hcd_t * hcd,
+00627                       dwc_hc_t * hc,
+00628                       dwc_otg_hc_regs_t * hc_regs,
+00629                       dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status)
+00630 {
+00631         dwc_otg_hcd_urb_t *urb = qtd->urb;
+00632         dwc_otg_halt_status_e ret_val = halt_status;
+00633         struct dwc_otg_hcd_iso_packet_desc *frame_desc;
+00634 
+00635         frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
+00636         switch (halt_status) {
+00637         case DWC_OTG_HC_XFER_COMPLETE:
+00638                 frame_desc->status = 0;
+00639                 frame_desc->actual_length =
+00640                     get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL);
+00641                     
+00642                 /* non DWORD-aligned buffer case handling. */
+00643                 if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) {
+00644                         dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset, 
+00645                                    hc->qh->dw_align_buf, frame_desc->actual_length);
+00646                 }
+00647                 
+00648                 break;
+00649         case DWC_OTG_HC_XFER_FRAME_OVERRUN:
+00650                 urb->error_count++;
+00651                 if (hc->ep_is_in) {
+00652                         frame_desc->status = -DWC_E_NO_STREAM_RES;
+00653                 } else {
+00654                         frame_desc->status = -DWC_E_COMMUNICATION;
+00655                 }
+00656                 frame_desc->actual_length = 0;
+00657                 break;
+00658         case DWC_OTG_HC_XFER_BABBLE_ERR:
+00659                 urb->error_count++;
+00660                 frame_desc->status = -DWC_E_OVERFLOW;
+00661                 /* Don't need to update actual_length in this case. */
+00662                 break;
+00663         case DWC_OTG_HC_XFER_XACT_ERR:
+00664                 urb->error_count++;
+00665                 frame_desc->status = -DWC_E_PROTOCOL;
+00666                 frame_desc->actual_length =
+00667                     get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL);
+00668                 
+00669                 /* non DWORD-aligned buffer case handling. */
+00670                 if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) {
+00671                         dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset, 
+00672                                    hc->qh->dw_align_buf, frame_desc->actual_length);
+00673                 }
+00674                 /* Skip whole frame */
+00675                 if (hc->qh->do_split && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && 
+00676                                 hc->ep_is_in && hcd->core_if->dma_enable) {
+00677                         qtd->complete_split = 0;
+00678                         qtd->isoc_split_offset = 0;
+00679                 }
+00680                         
+00681                 break;
+00682         default:
+00683                 DWC_ASSERT(1, "Unhandled _halt_status (%d)\n", halt_status);
+00684                 break;
+00685         }
+00686         if (++qtd->isoc_frame_index == urb->packet_count) {
+00687                 /*
+00688                  * urb->status is not used for isoc transfers.
+00689                  * The individual frame_desc statuses are used instead.
+00690                  */
+00691                 hcd->fops->complete(hcd, urb->priv, urb, 0);
+00692                 ret_val = DWC_OTG_HC_XFER_URB_COMPLETE;
+00693         } else {
+00694                 ret_val = DWC_OTG_HC_XFER_COMPLETE;
+00695         }
+00696         return ret_val;
+00697 }
+00698 
+00706 static void deactivate_qh(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, int free_qtd)
+00707 {
+00708         int continue_split = 0;
+00709         dwc_otg_qtd_t *qtd;
+00710 
+00711         DWC_DEBUGPL(DBG_HCDV, "  %s(%p,%p,%d)\n", __func__, hcd, qh, free_qtd);
+00712 
+00713         qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
+00714 
+00715         if (qtd->complete_split) {
+00716                 continue_split = 1;
+00717         } else if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID ||
+00718                    qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END) {
+00719                 continue_split = 1;
+00720         }
+00721 
+00722         if (free_qtd) {
+00723                 dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
+00724                 continue_split = 0;
+00725         }
+00726 
+00727         qh->channel = NULL;
+00728         dwc_otg_hcd_qh_deactivate(hcd, qh, continue_split);
+00729 }
+00730 
+00742 static void release_channel(dwc_otg_hcd_t * hcd,
+00743                             dwc_hc_t * hc,
+00744                             dwc_otg_qtd_t * qtd,
+00745                             dwc_otg_halt_status_e halt_status)
+00746 {
+00747         dwc_otg_transaction_type_e tr_type;
+00748         int free_qtd;
+00749 
+00750         DWC_DEBUGPL(DBG_HCDV, "  %s: channel %d, halt_status %d\n",
+00751                     __func__, hc->hc_num, halt_status);
+00752 
+00753         switch (halt_status) {
+00754         case DWC_OTG_HC_XFER_URB_COMPLETE:
+00755                 free_qtd = 1;
+00756                 break;
+00757         case DWC_OTG_HC_XFER_AHB_ERR:
+00758         case DWC_OTG_HC_XFER_STALL:
+00759         case DWC_OTG_HC_XFER_BABBLE_ERR:
+00760                 free_qtd = 1;
+00761                 break;
+00762         case DWC_OTG_HC_XFER_XACT_ERR:
+00763                 if (qtd->error_count >= 3) {
+00764                         DWC_DEBUGPL(DBG_HCDV,
+00765                                     "  Complete URB with transaction error\n");
+00766                         free_qtd = 1;
+00767                         qtd->urb->status = -DWC_E_PROTOCOL;
+00768                         hcd->fops->complete(hcd, qtd->urb->priv,
+00769                                             qtd->urb, -DWC_E_PROTOCOL);
+00770                 } else {
+00771                         free_qtd = 0;
+00772                 }
+00773                 break;
+00774         case DWC_OTG_HC_XFER_URB_DEQUEUE:
+00775                 /*
+00776                  * The QTD has already been removed and the QH has been
+00777                  * deactivated. Don't want to do anything except release the
+00778                  * host channel and try to queue more transfers.
+00779                  */
+00780                 goto cleanup;
+00781         case DWC_OTG_HC_XFER_NO_HALT_STATUS:
+00782                 free_qtd = 0;
+00783                 break;
+00784         default:
+00785                 free_qtd = 0;
+00786                 break;
+00787         }
+00788 
+00789         deactivate_qh(hcd, hc->qh, free_qtd);
+00790 
+00791       cleanup:
+00792         /*
+00793          * Release the host channel for use by other transfers. The cleanup
+00794          * function clears the channel interrupt enables and conditions, so
+00795          * there's no need to clear the Channel Halted interrupt separately.
+00796          */
+00797         dwc_otg_hc_cleanup(hcd->core_if, hc);
+00798         DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
+00799 
+00800         switch (hc->ep_type) {
+00801         case DWC_OTG_EP_TYPE_CONTROL:
+00802         case DWC_OTG_EP_TYPE_BULK:
+00803                 hcd->non_periodic_channels--;
+00804                 break;
+00805 
+00806         default:
+00807                 /*
+00808                  * Don't release reservations for periodic channels here.
+00809                  * That's done when a periodic transfer is descheduled (i.e.
+00810                  * when the QH is removed from the periodic schedule).
+00811                  */
+00812                 break;
+00813         }
+00814 
+00815         /* Try to queue more transfers now that there's a free channel. */
+00816         tr_type = dwc_otg_hcd_select_transactions(hcd);
+00817         if (tr_type != DWC_OTG_TRANSACTION_NONE) {
+00818                 dwc_otg_hcd_queue_transactions(hcd, tr_type);
+00819         }
+00820 }
+00821 
+00822 
+00833 static void halt_channel(dwc_otg_hcd_t * hcd,
+00834                          dwc_hc_t * hc,
+00835                          dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status)
+00836 {
+00837         if (hcd->core_if->dma_enable) {
+00838                 release_channel(hcd, hc, qtd, halt_status);
+00839                 return;
+00840         }
+00841 
+00842         /* Slave mode processing... */
+00843         dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
+00844 
+00845         if (hc->halt_on_queue) {
+00846                 gintmsk_data_t gintmsk = {.d32 = 0 };
+00847                 dwc_otg_core_global_regs_t *global_regs;
+00848                 global_regs = hcd->core_if->core_global_regs;
+00849 
+00850                 if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
+00851                     hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
+00852                         /*
+00853                          * Make sure the Non-periodic Tx FIFO empty interrupt
+00854                          * is enabled so that the non-periodic schedule will
+00855                          * be processed.
+00856                          */
+00857                         gintmsk.b.nptxfempty = 1;
+00858                         dwc_modify_reg32(&global_regs->gintmsk, 0, gintmsk.d32);
+00859                 } else {
+00860                         /*
+00861                          * Move the QH from the periodic queued schedule to
+00862                          * the periodic assigned schedule. This allows the
+00863                          * halt to be queued when the periodic schedule is
+00864                          * processed.
+00865                          */
+00866                         DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
+00867                                            &hc->qh->qh_list_entry);
+00868 
+00869                         /*
+00870                          * Make sure the Periodic Tx FIFO Empty interrupt is
+00871                          * enabled so that the periodic schedule will be
+00872                          * processed.
+00873                          */
+00874                         gintmsk.b.ptxfempty = 1;
+00875                         dwc_modify_reg32(&global_regs->gintmsk, 0, gintmsk.d32);
+00876                 }
+00877         }
+00878 }
+00879 
+00885 static void complete_non_periodic_xfer(dwc_otg_hcd_t * hcd,
+00886                                        dwc_hc_t * hc,
+00887                                        dwc_otg_hc_regs_t * hc_regs,
+00888                                        dwc_otg_qtd_t * qtd,
+00889                                        dwc_otg_halt_status_e halt_status)
+00890 {
+00891         hcint_data_t hcint;
+00892 
+00893         qtd->error_count = 0;
+00894 
+00895         hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+00896         if (hcint.b.nyet) {
+00897                 /*
+00898                  * Got a NYET on the last transaction of the transfer. This
+00899                  * means that the endpoint should be in the PING state at the
+00900                  * beginning of the next transfer.
+00901                  */
+00902                 hc->qh->ping_state = 1;
+00903                 clear_hc_int(hc_regs, nyet);
+00904         }
+00905 
+00906         /*
+00907          * Always halt and release the host channel to make it available for
+00908          * more transfers. There may still be more phases for a control
+00909          * transfer or more data packets for a bulk transfer at this point,
+00910          * but the host channel is still halted. A channel will be reassigned
+00911          * to the transfer when the non-periodic schedule is processed after
+00912          * the channel is released. This allows transactions to be queued
+00913          * properly via dwc_otg_hcd_queue_transactions, which also enables the
+00914          * Tx FIFO Empty interrupt if necessary.
+00915          */
+00916         if (hc->ep_is_in) {
+00917                 /*
+00918                  * IN transfers in Slave mode require an explicit disable to
+00919                  * halt the channel. (In DMA mode, this call simply releases
+00920                  * the channel.)
+00921                  */
+00922                 halt_channel(hcd, hc, qtd, halt_status);
+00923         } else {
+00924                 /*
+00925                  * The channel is automatically disabled by the core for OUT
+00926                  * transfers in Slave mode.
+00927                  */
+00928                 release_channel(hcd, hc, qtd, halt_status);
+00929         }
+00930 }
+00931 
+00937 static void complete_periodic_xfer(dwc_otg_hcd_t * hcd,
+00938                                    dwc_hc_t * hc,
+00939                                    dwc_otg_hc_regs_t * hc_regs,
+00940                                    dwc_otg_qtd_t * qtd,
+00941                                    dwc_otg_halt_status_e halt_status)
+00942 {
+00943         hctsiz_data_t hctsiz;
+00944         qtd->error_count = 0;
+00945 
+00946         hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
+00947         if (!hc->ep_is_in || hctsiz.b.pktcnt == 0) {
+00948                 /* Core halts channel in these cases. */
+00949                 release_channel(hcd, hc, qtd, halt_status);
+00950         } else {
+00951                 /* Flush any outstanding requests from the Tx queue. */
+00952                 halt_channel(hcd, hc, qtd, halt_status);
+00953         }
+00954 }
+00955 
+00956 static int32_t handle_xfercomp_isoc_split_in(dwc_otg_hcd_t * hcd,
+00957                                              dwc_hc_t * hc,
+00958                                              dwc_otg_hc_regs_t * hc_regs,
+00959                                              dwc_otg_qtd_t * qtd)
+00960 {
+00961         uint32_t len;   
+00962         struct dwc_otg_hcd_iso_packet_desc *frame_desc;
+00963         frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
+00964                                 
+00965         len = get_actual_xfer_length(hc, hc_regs, qtd,
+00966                                      DWC_OTG_HC_XFER_COMPLETE,
+00967                                      NULL);
+00968                      
+00969         if (!len) {
+00970                 qtd->complete_split = 0;
+00971                 qtd->isoc_split_offset = 0;
+00972                 return 0;
+00973         }
+00974         frame_desc->actual_length += len;
+00975         
+00976         if (hc->align_buff && len)
+00977                 dwc_memcpy(qtd->urb->buf + frame_desc->offset + qtd->isoc_split_offset, 
+00978                                                                 hc->qh->dw_align_buf, 
+00979                                                                 len);
+00980         qtd->isoc_split_offset += len;
+00981         
+00982         if (frame_desc->length == frame_desc->actual_length) {
+00983                 frame_desc->status = 0;
+00984                 qtd->isoc_frame_index++;
+00985                 qtd->complete_split = 0;
+00986                 qtd->isoc_split_offset = 0;
+00987         }
+00988                         
+00989         if (qtd->isoc_frame_index == qtd->urb->packet_count) {
+00990                 hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
+00991                 release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
+00992         } else {
+00993                 release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
+00994         }
+00995         
+00996         return 1; /* Indicates that channel released */
+00997 }
+01002 static int32_t handle_hc_xfercomp_intr(dwc_otg_hcd_t * hcd,
+01003                                        dwc_hc_t * hc,
+01004                                        dwc_otg_hc_regs_t * hc_regs,
+01005                                        dwc_otg_qtd_t * qtd)
+01006 {
+01007         int urb_xfer_done;
+01008         dwc_otg_halt_status_e halt_status = DWC_OTG_HC_XFER_COMPLETE;
+01009         dwc_otg_hcd_urb_t *urb = qtd->urb;
+01010         int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
+01011 
+01012         DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+01013                     "Transfer Complete--\n", hc->hc_num);
+01014 
+01015         if (hcd->core_if->dma_desc_enable) {
+01016                 dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, halt_status);
+01017                 if (pipe_type == UE_ISOCHRONOUS) {
+01018                         /* Do not disable the interrupt, just clear it */       
+01019                         clear_hc_int(hc_regs, xfercomp);
+01020                         return 1;
+01021                 }
+01022                 goto handle_xfercomp_done;
+01023         }
+01024 
+01025         /*
+01026          * Handle xfer complete on CSPLIT.
+01027          */
+01028 
+01029         if (hc->qh->do_split) {
+01030                 if ((hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && hc->ep_is_in && hcd->core_if->dma_enable) {
+01031                         if (qtd->complete_split && handle_xfercomp_isoc_split_in(hcd, hc, hc_regs, qtd))
+01032                                 goto handle_xfercomp_done;
+01033                 }
+01034                 else {
+01035                 qtd->complete_split = 0;
+01036         }
+01037         }       
+01038 
+01039         /* Update the QTD and URB states. */
+01040         switch (pipe_type) {
+01041         case UE_CONTROL:
+01042                 switch (qtd->control_phase) {
+01043                 case DWC_OTG_CONTROL_SETUP:
+01044                         if (urb->length > 0) {
+01045                                 qtd->control_phase = DWC_OTG_CONTROL_DATA;
+01046                         } else {
+01047                                 qtd->control_phase = DWC_OTG_CONTROL_STATUS;
+01048                         }
+01049                         DWC_DEBUGPL(DBG_HCDV,
+01050                                     "  Control setup transaction done\n");
+01051                         halt_status = DWC_OTG_HC_XFER_COMPLETE;
+01052                         break;
+01053                 case DWC_OTG_CONTROL_DATA:{
+01054                                 urb_xfer_done =
+01055                                     update_urb_state_xfer_comp(hc, hc_regs, urb,
+01056                                                                qtd);
+01057                                 if (urb_xfer_done) {
+01058                                         qtd->control_phase =
+01059                                             DWC_OTG_CONTROL_STATUS;
+01060                                         DWC_DEBUGPL(DBG_HCDV,
+01061                                                     "  Control data transfer done\n");
+01062                                 } else {
+01063                                         dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
+01064                                 }
+01065                                 halt_status = DWC_OTG_HC_XFER_COMPLETE;
+01066                                 break;
+01067                         }
+01068                 case DWC_OTG_CONTROL_STATUS:
+01069                         DWC_DEBUGPL(DBG_HCDV, "  Control transfer complete\n");
+01070                         if (urb->status == -DWC_E_IN_PROGRESS) {
+01071                                 urb->status = 0;
+01072                         }
+01073                         hcd->fops->complete(hcd, urb->priv, urb, urb->status);
+01074                         halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
+01075                         break;
+01076                 }
+01077 
+01078                 complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
+01079                 break;
+01080         case UE_BULK:
+01081                 DWC_DEBUGPL(DBG_HCDV, "  Bulk transfer complete\n");
+01082                 urb_xfer_done =
+01083                     update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
+01084                 if (urb_xfer_done) {
+01085                         hcd->fops->complete(hcd, urb->priv, urb, urb->status);
+01086                         halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
+01087                 } else {
+01088                         halt_status = DWC_OTG_HC_XFER_COMPLETE;
+01089                 }
+01090 
+01091                 dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
+01092                 complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
+01093                 break;
+01094         case UE_INTERRUPT:
+01095                 DWC_DEBUGPL(DBG_HCDV, "  Interrupt transfer complete\n");
+01096                 update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
+01097 
+01098                 /*
+01099                  * Interrupt URB is done on the first transfer complete
+01100                  * interrupt.
+01101                  */
+01102                 hcd->fops->complete(hcd, urb->priv, urb, urb->status);
+01103                 dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
+01104                 complete_periodic_xfer(hcd, hc, hc_regs, qtd,
+01105                                        DWC_OTG_HC_XFER_URB_COMPLETE);
+01106                 break;
+01107         case UE_ISOCHRONOUS:
+01108                 DWC_DEBUGPL(DBG_HCDV, "  Isochronous transfer complete\n");
+01109                 if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_ALL) {
+01110                         halt_status =
+01111                             update_isoc_urb_state(hcd, hc, hc_regs, qtd,
+01112                                                   DWC_OTG_HC_XFER_COMPLETE);
+01113                 }
+01114                 complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
+01115                 break;
+01116         }
+01117 
+01118 handle_xfercomp_done:
+01119         disable_hc_int(hc_regs, xfercompl);
+01120 
+01121         return 1;
+01122 }
+01123 
+01128 static int32_t handle_hc_stall_intr(dwc_otg_hcd_t * hcd,
+01129                                     dwc_hc_t * hc,
+01130                                     dwc_otg_hc_regs_t * hc_regs,
+01131                                     dwc_otg_qtd_t * qtd)
+01132 {
+01133         dwc_otg_hcd_urb_t *urb = qtd->urb;
+01134         int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
+01135 
+01136         DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+01137                     "STALL Received--\n", hc->hc_num);
+01138 
+01139         if (hcd->core_if->dma_desc_enable) {
+01140                 dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_STALL);
+01141                 goto handle_stall_done;
+01142         }
+01143 
+01144         if (pipe_type == UE_CONTROL) {
+01145                 hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
+01146         }
+01147 
+01148         if (pipe_type == UE_BULK || pipe_type == UE_INTERRUPT) {
+01149                 hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
+01150                 /*
+01151                  * USB protocol requires resetting the data toggle for bulk
+01152                  * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT)
+01153                  * setup command is issued to the endpoint. Anticipate the
+01154                  * CLEAR_FEATURE command since a STALL has occurred and reset
+01155                  * the data toggle now.
+01156                  */
+01157                 hc->qh->data_toggle = 0;
+01158         }
+01159 
+01160         halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_STALL);
+01161 
+01162 handle_stall_done:
+01163         disable_hc_int(hc_regs, stall);
+01164 
+01165         return 1;
+01166 }
+01167 
+01168 /*
+01169  * Updates the state of the URB when a transfer has been stopped due to an
+01170  * abnormal condition before the transfer completes. Modifies the
+01171  * actual_length field of the URB to reflect the number of bytes that have
+01172  * actually been transferred via the host channel.
+01173  */
+01174 static void update_urb_state_xfer_intr(dwc_hc_t * hc,
+01175                                        dwc_otg_hc_regs_t * hc_regs,
+01176                                        dwc_otg_hcd_urb_t * urb,
+01177                                        dwc_otg_qtd_t * qtd,
+01178                                        dwc_otg_halt_status_e halt_status)
+01179 {
+01180         uint32_t bytes_transferred = get_actual_xfer_length(hc, hc_regs, qtd,
+01181                                                             halt_status, NULL);
+01182         /* non DWORD-aligned buffer case handling. */
+01183         if (hc->align_buff && bytes_transferred && hc->ep_is_in) {
+01184                 dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf, bytes_transferred);
+01185         }
+01186         
+01187         urb->actual_length += bytes_transferred;
+01188 
+01189 #ifdef DEBUG
+01190         {
+01191                 hctsiz_data_t hctsiz;
+01192                 hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
+01193                 DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
+01194                             __func__, (hc->ep_is_in ? "IN" : "OUT"),
+01195                             hc->hc_num);
+01196                 DWC_DEBUGPL(DBG_HCDV, "  hc->start_pkt_count %d\n",
+01197                             hc->start_pkt_count);
+01198                 DWC_DEBUGPL(DBG_HCDV, "  hctsiz.pktcnt %d\n", hctsiz.b.pktcnt);
+01199                 DWC_DEBUGPL(DBG_HCDV, "  hc->max_packet %d\n", hc->max_packet);
+01200                 DWC_DEBUGPL(DBG_HCDV, "  bytes_transferred %d\n",
+01201                             bytes_transferred);
+01202                 DWC_DEBUGPL(DBG_HCDV, "  urb->actual_length %d\n",
+01203                             urb->actual_length);
+01204                 DWC_DEBUGPL(DBG_HCDV, "  urb->transfer_buffer_length %d\n",
+01205                             urb->length);
+01206         }
+01207 #endif
+01208 }
+01209 
+01214 static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd,
+01215                                   dwc_hc_t * hc,
+01216                                   dwc_otg_hc_regs_t * hc_regs,
+01217                                   dwc_otg_qtd_t * qtd)
+01218 {
+01219         DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+01220                     "NAK Received--\n", hc->hc_num);
+01221 
+01222         /*
+01223          * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
+01224          * interrupt.  Re-start the SSPLIT transfer.
+01225          */
+01226         if (hc->do_split) {
+01227                 if (hc->complete_split) {
+01228                         qtd->error_count = 0;
+01229                 }
+01230                 qtd->complete_split = 0;
+01231                 halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
+01232                 goto handle_nak_done;
+01233         }
+01234 
+01235         switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
+01236         case UE_CONTROL:
+01237         case UE_BULK:
+01238                 if (hcd->core_if->dma_enable && hc->ep_is_in) {
+01239                         /*
+01240                          * NAK interrupts are enabled on bulk/control IN
+01241                          * transfers in DMA mode for the sole purpose of
+01242                          * resetting the error count after a transaction error
+01243                          * occurs. The core will continue transferring data.
+01244                          */
+01245                         qtd->error_count = 0;
+01246                         goto handle_nak_done;
+01247                 }
+01248 
+01249                 /*
+01250                  * NAK interrupts normally occur during OUT transfers in DMA
+01251                  * or Slave mode. For IN transfers, more requests will be
+01252                  * queued as request queue space is available.
+01253                  */
+01254                 qtd->error_count = 0;
+01255 
+01256                 if (!hc->qh->ping_state) {
+01257                         update_urb_state_xfer_intr(hc, hc_regs,
+01258                                                    qtd->urb, qtd,
+01259                                                    DWC_OTG_HC_XFER_NAK);
+01260                         dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
+01261 
+01262                         if (hc->speed == DWC_OTG_EP_SPEED_HIGH)
+01263                                 hc->qh->ping_state = 1;
+01264                         }
+01265 
+01266                 /*
+01267                  * Halt the channel so the transfer can be re-started from
+01268                  * the appropriate point or the PING protocol will
+01269                  * start/continue.
+01270                  */
+01271                 halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
+01272                 break;
+01273         case UE_INTERRUPT:
+01274                 qtd->error_count = 0;
+01275                 halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
+01276                 break;
+01277         case UE_ISOCHRONOUS:
+01278                 /* Should never get called for isochronous transfers. */
+01279                 DWC_ASSERT(1, "NACK interrupt for ISOC transfer\n");
+01280                 break;
+01281         }
+01282 
+01283       handle_nak_done:
+01284         disable_hc_int(hc_regs, nak);
+01285 
+01286         return 1;
+01287 }
+01288 
+01294 static int32_t handle_hc_ack_intr(dwc_otg_hcd_t * hcd,
+01295                                   dwc_hc_t * hc,
+01296                                   dwc_otg_hc_regs_t * hc_regs,
+01297                                   dwc_otg_qtd_t * qtd)
+01298 {
+01299         DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+01300                     "ACK Received--\n", hc->hc_num);
+01301 
+01302         if (hc->do_split) {
+01303                 /*
+01304                  * Handle ACK on SSPLIT.
+01305                  * ACK should not occur in CSPLIT.
+01306                  */
+01307                 if (!hc->ep_is_in && hc->data_pid_start != DWC_OTG_HC_PID_SETUP) {
+01308                         qtd->ssplit_out_xfer_count = hc->xfer_len;
+01309                 }
+01310                 if (!(hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in)) {
+01311                         /* Don't need complete for isochronous out transfers. */
+01312                         qtd->complete_split = 1;
+01313                 }
+01314 
+01315                 /* ISOC OUT */
+01316                 if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) {
+01317                         switch (hc->xact_pos) {
+01318                         case DWC_HCSPLIT_XACTPOS_ALL:
+01319                                 break;
+01320                         case DWC_HCSPLIT_XACTPOS_END:
+01321                                 qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
+01322                                 qtd->isoc_split_offset = 0;
+01323                                 break;
+01324                         case DWC_HCSPLIT_XACTPOS_BEGIN:
+01325                         case DWC_HCSPLIT_XACTPOS_MID:
+01326                                 /*
+01327                                  * For BEGIN or MID, calculate the length for
+01328                                  * the next microframe to determine the correct
+01329                                  * SSPLIT token, either MID or END.
+01330                                  */
+01331                                 {
+01332                                         struct dwc_otg_hcd_iso_packet_desc
+01333                                             *frame_desc;
+01334 
+01335                                         frame_desc =
+01336                                             &qtd->urb->iso_descs[qtd->
+01337                                                                          isoc_frame_index];
+01338                                         qtd->isoc_split_offset += 188;
+01339 
+01340                                         if ((frame_desc->length -
+01341                                              qtd->isoc_split_offset) <= 188) {
+01342                                                 qtd->isoc_split_pos =
+01343                                                     DWC_HCSPLIT_XACTPOS_END;
+01344                                         } else {
+01345                                                 qtd->isoc_split_pos =
+01346                                                     DWC_HCSPLIT_XACTPOS_MID;
+01347                                         }
+01348 
+01349                                 }
+01350                                 break;
+01351                         }
+01352                 } else {
+01353                         halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
+01354                 }
+01355         } else {
+01356                 qtd->error_count = 0;
+01357 
+01358                 if (hc->qh->ping_state) {
+01359                         hc->qh->ping_state = 0;
+01360                         /*
+01361                          * Halt the channel so the transfer can be re-started
+01362                          * from the appropriate point. This only happens in
+01363                          * Slave mode. In DMA mode, the ping_state is cleared
+01364                          * when the transfer is started because the core
+01365                          * automatically executes the PING, then the transfer.
+01366                          */
+01367                         halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
+01368                 }
+01369         }
+01370 
+01371         /*
+01372          * If the ACK occurred when _not_ in the PING state, let the channel
+01373          * continue transferring data after clearing the error count.
+01374          */
+01375 
+01376         disable_hc_int(hc_regs, ack);
+01377 
+01378         return 1;
+01379 }
+01380 
+01388 static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * hcd,
+01389                                    dwc_hc_t * hc,
+01390                                    dwc_otg_hc_regs_t * hc_regs,
+01391                                    dwc_otg_qtd_t * qtd)
+01392 {
+01393         DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+01394                     "NYET Received--\n", hc->hc_num);
+01395 
+01396         /*
+01397          * NYET on CSPLIT
+01398          * re-do the CSPLIT immediately on non-periodic
+01399          */
+01400         if (hc->do_split && hc->complete_split) {
+01401                 if (hc->ep_is_in && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && hcd->core_if->dma_enable) {        
+01402                         qtd->complete_split = 0;
+01403                         qtd->isoc_split_offset = 0;
+01404                         if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
+01405                                 hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
+01406                                 release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);    
+01407                         }
+01408                         else
+01409                                 release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);  
+01410                         goto handle_nyet_done;
+01411                 }
+01412                 
+01413                 if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
+01414                     hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+01415                         int frnum = dwc_otg_hcd_get_frame_number(hcd);
+01416 
+01417                         if (dwc_full_frame_num(frnum) !=
+01418                             dwc_full_frame_num(hc->qh->sched_frame)) {
+01419                                 /*
+01420                                  * No longer in the same full speed frame.
+01421                                  * Treat this as a transaction error.
+01422                                  */
+01423 #if 0
+01424 
+01430                                 qtd->error_count++;
+01431 #endif
+01432                                 qtd->complete_split = 0;
+01433                                 halt_channel(hcd, hc, qtd,
+01434                                              DWC_OTG_HC_XFER_XACT_ERR);
+01436                                 goto handle_nyet_done;
+01437                         }
+01438                 }
+01439 
+01440                 halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
+01441                 goto handle_nyet_done;
+01442         }
+01443 
+01444         hc->qh->ping_state = 1;
+01445         qtd->error_count = 0;
+01446 
+01447         update_urb_state_xfer_intr(hc, hc_regs, qtd->urb, qtd,
+01448                                    DWC_OTG_HC_XFER_NYET);
+01449         dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
+01450 
+01451         /*
+01452          * Halt the channel and re-start the transfer so the PING
+01453          * protocol will start.
+01454          */
+01455         halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
+01456 
+01457       handle_nyet_done:
+01458         disable_hc_int(hc_regs, nyet);
+01459         return 1;
+01460 }
+01461 
+01466 static int32_t handle_hc_babble_intr(dwc_otg_hcd_t * hcd,
+01467                                      dwc_hc_t * hc,
+01468                                      dwc_otg_hc_regs_t * hc_regs,
+01469                                      dwc_otg_qtd_t * qtd)
+01470 {
+01471         DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+01472                     "Babble Error--\n", hc->hc_num);
+01473         
+01474         if (hcd->core_if->dma_desc_enable) {
+01475                 dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_BABBLE_ERR);
+01476                 goto handle_babble_done;
+01477         }
+01478 
+01479         if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
+01480                 hcd->fops->complete(hcd, qtd->urb->priv,
+01481                                     qtd->urb, -DWC_E_OVERFLOW);
+01482                 halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_BABBLE_ERR);
+01483         } else {
+01484                 dwc_otg_halt_status_e halt_status;
+01485                 halt_status = update_isoc_urb_state(hcd, hc, hc_regs, qtd,
+01486                                                     DWC_OTG_HC_XFER_BABBLE_ERR);
+01487                 halt_channel(hcd, hc, qtd, halt_status);
+01488         }
+01489         
+01490 handle_babble_done:
+01491         disable_hc_int(hc_regs, bblerr);
+01492         return 1;
+01493 }
+01494 
+01499 static int32_t handle_hc_ahberr_intr(dwc_otg_hcd_t * hcd,
+01500                                      dwc_hc_t * hc,
+01501                                      dwc_otg_hc_regs_t * hc_regs,
+01502                                      dwc_otg_qtd_t * qtd)
+01503 {
+01504         hcchar_data_t hcchar;
+01505         hcsplt_data_t hcsplt;
+01506         hctsiz_data_t hctsiz;
+01507         uint32_t hcdma;
+01508         char *pipetype, *speed;
+01509 
+01510         dwc_otg_hcd_urb_t *urb = qtd->urb;
+01511 
+01512         DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+01513                     "AHB Error--\n", hc->hc_num);
+01514 
+01515         hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01516         hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt);
+01517         hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
+01518         hcdma = dwc_read_reg32(&hc_regs->hcdma);
+01519 
+01520         DWC_ERROR("AHB ERROR, Channel %d\n", hc->hc_num);
+01521         DWC_ERROR("  hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32);
+01522         DWC_ERROR("  hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma);
+01523         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Enqueue\n");
+01524         DWC_ERROR("  Device address: %d\n",
+01525                   dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
+01526         DWC_ERROR("  Endpoint: %d, %s\n",
+01527                   dwc_otg_hcd_get_ep_num(&urb->pipe_info),
+01528                   (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT"));
+01529         
+01530 
+01531         switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) {
+01532 case UE_CONTROL:
+01533                 pipetype = "CONTROL"; 
+01534                 break; 
+01535         case UE_BULK:
+01536                 pipetype = "BULK"; 
+01537                 break; 
+01538         case UE_INTERRUPT:
+01539                 pipetype = "INTERRUPT"; 
+01540                 break; 
+01541         case UE_ISOCHRONOUS:
+01542                 pipetype = "ISOCHRONOUS"; 
+01543                 break; 
+01544         default:
+01545                 pipetype = "UNKNOWN"; 
+01546                 break;
+01547         }
+01548         
+01549         DWC_ERROR("  Endpoint type: %s\n", pipetype);
+01550 
+01551         switch (hc->speed) {
+01552         case DWC_OTG_EP_SPEED_HIGH:
+01553                 speed = "HIGH"; 
+01554                 break; 
+01555         case DWC_OTG_EP_SPEED_FULL:
+01556                 speed = "FULL"; 
+01557                 break; 
+01558         case DWC_OTG_EP_SPEED_LOW:
+01559                 speed = "LOW"; 
+01560                 break; 
+01561         default:
+01562                 speed = "UNKNOWN"; 
+01563                 break;
+01564         };      
+01565 
+01566         DWC_ERROR("  Speed: %s\n", speed);
+01567         
+01568         DWC_ERROR("  Max packet size: %d\n",
+01569                   dwc_otg_hcd_get_mps(&urb->pipe_info));
+01570         DWC_ERROR("  Data buffer length: %d\n", urb->length);
+01571         DWC_ERROR("  Transfer buffer: %p, Transfer DMA: %p\n",
+01572                   urb->buf, (void *)urb->dma);
+01573         DWC_ERROR("  Setup buffer: %p, Setup DMA: %p\n",
+01574                   urb->setup_packet, (void *)urb->setup_dma);
+01575         DWC_ERROR("  Interval: %d\n", urb->interval);
+01576 
+01577         /* Core haltes the channel for Descriptor DMA mode */
+01578         if (hcd->core_if->dma_desc_enable) {
+01579                 dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_AHB_ERR);
+01580                 goto handle_ahberr_done;
+01581         }
+01582 
+01583         hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_IO);
+01584 
+01585         /*
+01586          * Force a channel halt. Don't call halt_channel because that won't
+01587          * write to the HCCHARn register in DMA mode to force the halt.
+01588          */
+01589         dwc_otg_hc_halt(hcd->core_if, hc, DWC_OTG_HC_XFER_AHB_ERR);
+01590 handle_ahberr_done:
+01591         disable_hc_int(hc_regs, ahberr);
+01592         return 1;
+01593 }
+01594 
+01599 static int32_t handle_hc_xacterr_intr(dwc_otg_hcd_t * hcd,
+01600                                       dwc_hc_t * hc,
+01601                                       dwc_otg_hc_regs_t * hc_regs,
+01602                                       dwc_otg_qtd_t * qtd)
+01603 {
+01604         DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+01605                     "Transaction Error--\n", hc->hc_num);
+01606 
+01607         if (hcd->core_if->dma_desc_enable) {
+01608                 dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_XACT_ERR);
+01609                 goto handle_xacterr_done;
+01610         }
+01611 
+01612         switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
+01613         case UE_CONTROL:
+01614         case UE_BULK:
+01615                 qtd->error_count++;
+01616                 if (!hc->qh->ping_state) {
+01617 
+01618                         update_urb_state_xfer_intr(hc, hc_regs,
+01619                                                    qtd->urb, qtd,
+01620                                                    DWC_OTG_HC_XFER_XACT_ERR);
+01621                         dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
+01622                         if (!hc->ep_is_in && hc->speed == DWC_OTG_EP_SPEED_HIGH) {
+01623                                 hc->qh->ping_state = 1;
+01624                         }
+01625                 }
+01626 
+01627                 /*
+01628                  * Halt the channel so the transfer can be re-started from
+01629                  * the appropriate point or the PING protocol will start.
+01630                  */
+01631                 halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
+01632                 break;
+01633         case UE_INTERRUPT:
+01634                 qtd->error_count++;
+01635                 if (hc->do_split && hc->complete_split) {
+01636                         qtd->complete_split = 0;
+01637                 }
+01638                 halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
+01639                 break;
+01640         case UE_ISOCHRONOUS:
+01641                 {
+01642                         dwc_otg_halt_status_e halt_status;
+01643                         halt_status =
+01644                             update_isoc_urb_state(hcd, hc, hc_regs, qtd,
+01645                                                   DWC_OTG_HC_XFER_XACT_ERR);
+01646 
+01647                         halt_channel(hcd, hc, qtd, halt_status);
+01648                 }
+01649                 break;
+01650         }
+01651 handle_xacterr_done:
+01652         disable_hc_int(hc_regs, xacterr);
+01653 
+01654         return 1;
+01655 }
+01656 
+01661 static int32_t handle_hc_frmovrun_intr(dwc_otg_hcd_t * hcd,
+01662                                        dwc_hc_t * hc,
+01663                                        dwc_otg_hc_regs_t * hc_regs,
+01664                                        dwc_otg_qtd_t * qtd)
+01665 {
+01666         DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+01667                     "Frame Overrun--\n", hc->hc_num);
+01668 
+01669         switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
+01670         case UE_CONTROL:
+01671         case UE_BULK:
+01672                 break;
+01673         case UE_INTERRUPT:
+01674                 halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_FRAME_OVERRUN);
+01675                 break;
+01676         case UE_ISOCHRONOUS:
+01677                 {
+01678                         dwc_otg_halt_status_e halt_status;
+01679                         halt_status =
+01680                             update_isoc_urb_state(hcd, hc, hc_regs, qtd,
+01681                                                   DWC_OTG_HC_XFER_FRAME_OVERRUN);
+01682 
+01683                         halt_channel(hcd, hc, qtd, halt_status);
+01684                 }
+01685                 break;
+01686         }
+01687 
+01688         disable_hc_int(hc_regs, frmovrun);
+01689 
+01690         return 1;
+01691 }
+01692 
+01697 static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t * hcd,
+01698                                          dwc_hc_t * hc,
+01699                                          dwc_otg_hc_regs_t * hc_regs,
+01700                                          dwc_otg_qtd_t * qtd)
+01701 {
+01702         DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+01703                     "Data Toggle Error--\n", hc->hc_num);
+01704 
+01705         if (hc->ep_is_in) {
+01706                 qtd->error_count = 0;
+01707         } else {
+01708                 DWC_ERROR("Data Toggle Error on OUT transfer,"
+01709                           "channel %d\n", hc->hc_num);
+01710         }
+01711 
+01712         disable_hc_int(hc_regs, datatglerr);
+01713 
+01714         return 1;
+01715 }
+01716 
+01717 #ifdef DEBUG
+01718 
+01724 static inline int halt_status_ok(dwc_otg_hcd_t * hcd,
+01725                                  dwc_hc_t * hc,
+01726                                  dwc_otg_hc_regs_t * hc_regs,
+01727                                  dwc_otg_qtd_t * qtd)
+01728 {
+01729         hcchar_data_t hcchar;
+01730         hctsiz_data_t hctsiz;
+01731         hcint_data_t hcint;
+01732         hcintmsk_data_t hcintmsk;
+01733         hcsplt_data_t hcsplt;
+01734 
+01735         if (hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS) {
+01736                 /*
+01737                  * This code is here only as a check. This condition should
+01738                  * never happen. Ignore the halt if it does occur.
+01739                  */
+01740                 hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01741                 hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
+01742                 hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+01743                 hcintmsk.d32 = dwc_read_reg32(&hc_regs->hcintmsk);
+01744                 hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt);
+01745                 DWC_WARN
+01746                     ("%s: hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS, "
+01747                      "channel %d, hcchar 0x%08x, hctsiz 0x%08x, "
+01748                      "hcint 0x%08x, hcintmsk 0x%08x, "
+01749                      "hcsplt 0x%08x, qtd->complete_split %d\n", __func__,
+01750                      hc->hc_num, hcchar.d32, hctsiz.d32, hcint.d32,
+01751                      hcintmsk.d32, hcsplt.d32, qtd->complete_split);
+01752 
+01753                 DWC_WARN("%s: no halt status, channel %d, ignoring interrupt\n",
+01754                          __func__, hc->hc_num);
+01755                 DWC_WARN("\n");
+01756                 clear_hc_int(hc_regs, chhltd);
+01757                 return 0;
+01758         }
+01759 
+01760         /*
+01761          * This code is here only as a check. hcchar.chdis should
+01762          * never be set when the halt interrupt occurs. Halt the
+01763          * channel again if it does occur.
+01764          */
+01765         hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+01766         if (hcchar.b.chdis) {
+01767                 DWC_WARN("%s: hcchar.chdis set unexpectedly, "
+01768                          "hcchar 0x%08x, trying to halt again\n",
+01769                          __func__, hcchar.d32);
+01770                 clear_hc_int(hc_regs, chhltd);
+01771                 hc->halt_pending = 0;
+01772                 halt_channel(hcd, hc, qtd, hc->halt_status);
+01773                 return 0;
+01774         }
+01775 
+01776         return 1;
+01777 }
+01778 #endif
+01779 
+01784 static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd,
+01785                                       dwc_hc_t * hc,
+01786                                       dwc_otg_hc_regs_t * hc_regs,
+01787                                       dwc_otg_qtd_t * qtd)
+01788 {
+01789         hcint_data_t hcint;
+01790         hcintmsk_data_t hcintmsk;
+01791         int out_nak_enh = 0;
+01792 
+01793         /* For core with OUT NAK enhancement, the flow for high-
+01794          * speed CONTROL/BULK OUT is handled a little differently.
+01795          */
+01796         if (hcd->core_if->snpsid >= OTG_CORE_REV_2_71a) {
+01797                 if (hc->speed == DWC_OTG_EP_SPEED_HIGH && !hc->ep_is_in &&
+01798                     (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
+01799                      hc->ep_type == DWC_OTG_EP_TYPE_BULK)) {
+01800                         out_nak_enh = 1;
+01801                 }
+01802         }
+01803 
+01804         if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
+01805             (hc->halt_status == DWC_OTG_HC_XFER_AHB_ERR && !hcd->core_if->dma_desc_enable)) {
+01806                 /*
+01807                  * Just release the channel. A dequeue can happen on a
+01808                  * transfer timeout. In the case of an AHB Error, the channel
+01809                  * was forced to halt because there's no way to gracefully
+01810                  * recover.
+01811                  */
+01812                 if (hcd->core_if->dma_desc_enable)
+01813                         dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, hc->halt_status);
+01814                 else
+01815                         release_channel(hcd, hc, qtd, hc->halt_status);
+01816                 return;
+01817         }
+01818 
+01819         /* Read the HCINTn register to determine the cause for the halt. */
+01820         hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+01821         hcintmsk.d32 = dwc_read_reg32(&hc_regs->hcintmsk);
+01822 
+01823         if (hcint.b.xfercomp) {
+01830                 if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) {
+01831                         handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
+01832                 }
+01833                 handle_hc_xfercomp_intr(hcd, hc, hc_regs, qtd);
+01834         } else if (hcint.b.stall) {
+01835                 handle_hc_stall_intr(hcd, hc, hc_regs, qtd);
+01836         } else if (hcint.b.xacterr && !hcd->core_if->dma_desc_enable) {
+01837                 if (out_nak_enh) {
+01838                         if (hcint.b.nyet || hcint.b.nak || hcint.b.ack) {
+01839                                 DWC_DEBUG("XactErr with NYET/NAK/ACK\n");
+01840                                 qtd->error_count = 0;
+01841                         } else {
+01842                                 DWC_DEBUG("XactErr without NYET/NAK/ACK\n");
+01843                         }
+01844                 }
+01845 
+01846                 /*
+01847                  * Must handle xacterr before nak or ack. Could get a xacterr
+01848                  * at the same time as either of these on a BULK/CONTROL OUT
+01849                  * that started with a PING. The xacterr takes precedence.
+01850                  */
+01851                 handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
+01852         } else if (hcint.b.xcs_xact && hcd->core_if->dma_desc_enable) {
+01853                 handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
+01854         } else if (hcint.b.ahberr && hcd->core_if->dma_desc_enable) {    
+01855                 handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd);
+01856         } else if (hcint.b.bblerr) {
+01857                 handle_hc_babble_intr(hcd, hc, hc_regs, qtd);
+01858         } else if (hcint.b.frmovrun) {
+01859                 handle_hc_frmovrun_intr(hcd, hc, hc_regs, qtd);
+01860         } else if (!out_nak_enh) {
+01861                 if (hcint.b.nyet) {
+01862                         /*
+01863                          * Must handle nyet before nak or ack. Could get a nyet at the
+01864                          * same time as either of those on a BULK/CONTROL OUT that
+01865                          * started with a PING. The nyet takes precedence.
+01866                          */
+01867                         handle_hc_nyet_intr(hcd, hc, hc_regs, qtd);
+01868                 } else if (hcint.b.nak && !hcintmsk.b.nak) {
+01869                         /*
+01870                          * If nak is not masked, it's because a non-split IN transfer
+01871                          * is in an error state. In that case, the nak is handled by
+01872                          * the nak interrupt handler, not here. Handle nak here for
+01873                          * BULK/CONTROL OUT transfers, which halt on a NAK to allow
+01874                          * rewinding the buffer pointer.
+01875                          */
+01876                         handle_hc_nak_intr(hcd, hc, hc_regs, qtd);
+01877                 } else if (hcint.b.ack && !hcintmsk.b.ack) {
+01878                         /*
+01879                          * If ack is not masked, it's because a non-split IN transfer
+01880                          * is in an error state. In that case, the ack is handled by
+01881                          * the ack interrupt handler, not here. Handle ack here for
+01882                          * split transfers. Start splits halt on ACK.
+01883                          */
+01884                         handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
+01885                 } else {
+01886                         if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
+01887                             hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+01888                                 /*
+01889                                  * A periodic transfer halted with no other channel
+01890                                  * interrupts set. Assume it was halted by the core
+01891                                  * because it could not be completed in its scheduled
+01892                                  * (micro)frame.
+01893                                  */
+01894 #ifdef DEBUG
+01895                                 DWC_PRINTF
+01896                                     ("%s: Halt channel %d (assume incomplete periodic transfer)\n",
+01897                                      __func__, hc->hc_num);
+01898 #endif
+01899                                 halt_channel(hcd, hc, qtd,
+01900                                              DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE);
+01901                         } else {
+01902                                 DWC_ERROR
+01903                                     ("%s: Channel %d, DMA Mode -- ChHltd set, but reason "
+01904                                      "for halting is unknown, hcint 0x%08x, intsts 0x%08x\n",
+01905                                      __func__, hc->hc_num, hcint.d32,
+01906                                      dwc_read_reg32(&hcd->core_if->
+01907                                                     core_global_regs->gintsts));
+01908                         }
+01909         
+01910                 }
+01911         } else {
+01912                 DWC_PRINTF("NYET/NAK/ACK/other in non-error case, 0x%08x\n",
+01913                            hcint.d32);
+01914         }
+01915 }
+01916 
+01928 static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd,
+01929                                      dwc_hc_t * hc,
+01930                                      dwc_otg_hc_regs_t * hc_regs,
+01931                                      dwc_otg_qtd_t * qtd)
+01932 {
+01933         DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+01934                     "Channel Halted--\n", hc->hc_num);
+01935 
+01936         if (hcd->core_if->dma_enable) {
+01937                 handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd);
+01938         } else {
+01939 #ifdef DEBUG
+01940                 if (!halt_status_ok(hcd, hc, hc_regs, qtd)) {
+01941                         return 1;
+01942                 }
+01943 #endif
+01944                 release_channel(hcd, hc, qtd, hc->halt_status);
+01945         }
+01946 
+01947         return 1;
+01948 }
+01949 
+01951 int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num)
+01952 {
+01953         int retval = 0;
+01954         hcint_data_t hcint;
+01955         hcintmsk_data_t hcintmsk;
+01956         dwc_hc_t *hc;
+01957         dwc_otg_hc_regs_t *hc_regs;
+01958         dwc_otg_qtd_t *qtd;
+01959 
+01960         DWC_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", num);
+01961 
+01962         hc = dwc_otg_hcd->hc_ptr_array[num];
+01963         hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[num];
+01964         qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list);
+01965 
+01966         hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+01967         hcintmsk.d32 = dwc_read_reg32(&hc_regs->hcintmsk);
+01968         DWC_DEBUGPL(DBG_HCDV,
+01969                     "  hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",
+01970                     hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32));
+01971         hcint.d32 = hcint.d32 & hcintmsk.d32;
+01972 
+01973         if (!dwc_otg_hcd->core_if->dma_enable) {
+01974                 if (hcint.b.chhltd && hcint.d32 != 0x2) {
+01975                         hcint.b.chhltd = 0;
+01976                 }
+01977         }
+01978 
+01979         if (hcint.b.xfercomp) {
+01980                 retval |=
+01981                     handle_hc_xfercomp_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+01982                 /*
+01983                  * If NYET occurred at same time as Xfer Complete, the NYET is
+01984                  * handled by the Xfer Complete interrupt handler. Don't want
+01985                  * to call the NYET interrupt handler in this case.
+01986                  */
+01987                 hcint.b.nyet = 0;
+01988         }
+01989         if (hcint.b.chhltd) {
+01990                 retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+01991         }
+01992         if (hcint.b.ahberr) {
+01993                 retval |= handle_hc_ahberr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+01994         }
+01995         if (hcint.b.stall) {
+01996                 retval |= handle_hc_stall_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+01997         }
+01998         if (hcint.b.nak) {
+01999                 retval |= handle_hc_nak_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+02000         }
+02001         if (hcint.b.ack) {
+02002                 retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+02003         }
+02004         if (hcint.b.nyet) {
+02005                 retval |= handle_hc_nyet_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+02006         }
+02007         if (hcint.b.xacterr) {
+02008                 retval |= handle_hc_xacterr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+02009         }
+02010         if (hcint.b.bblerr) {
+02011                 retval |= handle_hc_babble_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+02012         }
+02013         if (hcint.b.frmovrun) {
+02014                 retval |=
+02015                     handle_hc_frmovrun_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+02016         }
+02017         if (hcint.b.datatglerr) {
+02018                 retval |=
+02019                     handle_hc_datatglerr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+02020         }
+02021 
+02022         return retval;
+02023 }
+02024 
+02025 #endif                          /* DWC_DEVICE_ONLY */
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__intr_8c.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__intr_8c.html new file mode 100644 index 000000000000..49852d4bcce7 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__intr_8c.html @@ -0,0 +1,1252 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hcd_intr.c File Reference + + + + + + +

dwc_otg_hcd_intr.c File Reference

This file contains the implementation of the HCD Interrupt handlers. More... +

+#include "dwc_otg_hcd.h"
+#include "dwc_otg_regs.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Functions

int32_t dwc_otg_hcd_handle_intr (dwc_otg_hcd_t *dwc_otg_hcd)
 This function should be called on every hardware interrupt.
int32_t dwc_otg_hcd_handle_sof_intr (dwc_otg_hcd_t *hcd)
 Handles the start-of-frame interrupt in host mode.
int32_t dwc_otg_hcd_handle_rx_status_q_level_intr (dwc_otg_hcd_t *dwc_otg_hcd)
 Handles the Rx Status Queue Level Interrupt, which indicates that there is at least one packet in the Rx FIFO.
int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr (dwc_otg_hcd_t *dwc_otg_hcd)
 This interrupt occurs when the non-periodic Tx FIFO is half-empty.
int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr (dwc_otg_hcd_t *dwc_otg_hcd)
 This interrupt occurs when the periodic Tx FIFO is half-empty.
int32_t dwc_otg_hcd_handle_port_intr (dwc_otg_hcd_t *dwc_otg_hcd)
 There are multiple conditions that can cause a port interrupt.
int32_t dwc_otg_hcd_handle_hc_intr (dwc_otg_hcd_t *dwc_otg_hcd)
 This interrupt indicates that one or more host channels has a pending interrupt.
static uint32_t get_actual_xfer_length (dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_qtd_t *qtd, dwc_otg_halt_status_e halt_status, int *short_read)
 Gets the actual length of a transfer after the transfer halts.
static int update_urb_state_xfer_comp (dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_hcd_urb_t *urb, dwc_otg_qtd_t *qtd)
 Updates the state of the URB after a Transfer Complete interrupt on the host channel.
+void dwc_otg_hcd_save_data_toggle (dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_qtd_t *qtd)
static dwc_otg_halt_status_e update_isoc_urb_state (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_qtd_t *qtd, dwc_otg_halt_status_e halt_status)
 Updates the state of an Isochronous URB when the transfer is stopped for any reason.
static void deactivate_qh (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, int free_qtd)
 Frees the first QTD in the QH's list if free_qtd is 1.
static void release_channel (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_qtd_t *qtd, dwc_otg_halt_status_e halt_status)
 Releases a host channel for use by other transfers.
static void halt_channel (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_qtd_t *qtd, dwc_otg_halt_status_e halt_status)
 Halts a host channel.
static void complete_non_periodic_xfer (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_qtd_t *qtd, dwc_otg_halt_status_e halt_status)
 Performs common cleanup for non-periodic transfers after a Transfer Complete interrupt.
static void complete_periodic_xfer (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_qtd_t *qtd, dwc_otg_halt_status_e halt_status)
 Performs common cleanup for periodic transfers after a Transfer Complete interrupt.
+static int32_t handle_xfercomp_isoc_split_in (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_qtd_t *qtd)
static int32_t handle_hc_xfercomp_intr (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_qtd_t *qtd)
 Handles a host channel Transfer Complete interrupt.
static int32_t handle_hc_stall_intr (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_qtd_t *qtd)
 Handles a host channel STALL interrupt.
+static void update_urb_state_xfer_intr (dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_hcd_urb_t *urb, dwc_otg_qtd_t *qtd, dwc_otg_halt_status_e halt_status)
static int32_t handle_hc_nak_intr (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_qtd_t *qtd)
 Handles a host channel NAK interrupt.
static int32_t handle_hc_ack_intr (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_qtd_t *qtd)
 Handles a host channel ACK interrupt.
static int32_t handle_hc_nyet_intr (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_qtd_t *qtd)
 Handles a host channel NYET interrupt.
static int32_t handle_hc_babble_intr (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_qtd_t *qtd)
 Handles a host channel babble interrupt.
static int32_t handle_hc_ahberr_intr (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_qtd_t *qtd)
 Handles a host channel AHB error interrupt.
static int32_t handle_hc_xacterr_intr (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_qtd_t *qtd)
 Handles a host channel transaction error interrupt.
static int32_t handle_hc_frmovrun_intr (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_qtd_t *qtd)
 Handles a host channel frame overrun interrupt.
static int32_t handle_hc_datatglerr_intr (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_qtd_t *qtd)
 Handles a host channel data toggle error interrupt.
static void handle_hc_chhltd_intr_dma (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_qtd_t *qtd)
 Handles a host Channel Halted interrupt in DMA mode.
static int32_t handle_hc_chhltd_intr (dwc_otg_hcd_t *hcd, dwc_hc_t *hc, dwc_otg_hc_regs_t *hc_regs, dwc_otg_qtd_t *qtd)
 Handles a host channel Channel Halted interrupt.
+int32_t dwc_otg_hcd_handle_hc_n_intr (dwc_otg_hcd_t *dwc_otg_hcd, uint32_t num)
 Handles interrupt for a specific Host Channel.
+


Detailed Description

+This file contains the implementation of the HCD Interrupt handlers. +

+ +

+Definition in file dwc_otg_hcd_intr.c.


Function Documentation

+ +
+
+ + + + + + + + + +
int32_t dwc_otg_hcd_handle_intr (dwc_otg_hcd_t dwc_otg_hcd  ) 
+
+
+ +

+This function should be called on every hardware interrupt. +

+

Parameters:
+ + +
dwc_otg_hcd The HCD
+
+Returns non zero if interrupt is handled Return 0 if interrupt is not handled +

+

Todo:
Implement i2cintr handler.
+ +

+Definition at line 43 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_hcd_handle_sof_intr (dwc_otg_hcd_t hcd  ) 
+
+
+ +

+Handles the start-of-frame interrupt in host mode. +

+Non-periodic transactions may be queued to the DWC_otg controller for the current (micro)frame. Periodic transactions may be queued to the controller for the next (micro)frame. +

+Definition at line 169 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_hcd_handle_rx_status_q_level_intr (dwc_otg_hcd_t dwc_otg_hcd  ) 
+
+
+ +

+Handles the Rx Status Queue Level Interrupt, which indicates that there is at least one packet in the Rx FIFO. +

+The packets are moved from the FIFO to memory if the DWC_otg controller is operating in Slave mode. +

+Definition at line 222 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr (dwc_otg_hcd_t dwc_otg_hcd  ) 
+
+
+ +

+This interrupt occurs when the non-periodic Tx FIFO is half-empty. +

+More data packets may be written to the FIFO for OUT transfers. More requests may be written to the non-periodic request queue for IN transfers. This interrupt is enabled only in Slave mode. +

+Definition at line 271 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr (dwc_otg_hcd_t dwc_otg_hcd  ) 
+
+
+ +

+This interrupt occurs when the periodic Tx FIFO is half-empty. +

+More data packets may be written to the FIFO for OUT transfers. More requests may be written to the periodic request queue for IN transfers. This interrupt is enabled only in Slave mode. +

+Definition at line 283 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_hcd_handle_port_intr (dwc_otg_hcd_t dwc_otg_hcd  ) 
+
+
+ +

+There are multiple conditions that can cause a port interrupt. +

+This function determines which interrupt conditions have occurred and handles them appropriately. +

+Overcurrent Change Interrupt +

+Definition at line 294 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_hcd_handle_hc_intr (dwc_otg_hcd_t dwc_otg_hcd  ) 
+
+
+ +

+This interrupt indicates that one or more host channels has a pending interrupt. +

+There are multiple conditions that can cause each host channel interrupt. This function determines which conditions have occurred for each host channel interrupt and handles them appropriately. +

+Definition at line 453 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static uint32_t get_actual_xfer_length (dwc_hc_t hc,
dwc_otg_hc_regs_t hc_regs,
dwc_otg_qtd_t qtd,
dwc_otg_halt_status_e  halt_status,
int *  short_read 
) [static]
+
+
+ +

+Gets the actual length of a transfer after the transfer halts. +

+_halt_status holds the reason for the halt.

+For IN transfers where halt_status is DWC_OTG_HC_XFER_COMPLETE, *short_read is set to 1 upon return if less than the requested number of bytes were transferred. Otherwise, *short_read is set to 0 upon return. short_read may also be NULL on entry, in which case it remains unchanged. +

+Definition at line 485 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static int update_urb_state_xfer_comp (dwc_hc_t hc,
dwc_otg_hc_regs_t hc_regs,
dwc_otg_hcd_urb_t urb,
dwc_otg_qtd_t qtd 
) [static]
+
+
+ +

+Updates the state of the URB after a Transfer Complete interrupt on the host channel. +

+Updates the actual_length field of the URB based on the number of bytes transferred via the host channel. Sets the URB status if the data transfer is finished.

+

Returns:
1 if the data transfer specified by the URB is completely finished, 0 otherwise.
+ +

+Definition at line 536 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static dwc_otg_halt_status_e update_isoc_urb_state (dwc_otg_hcd_t hcd,
dwc_hc_t hc,
dwc_otg_hc_regs_t hc_regs,
dwc_otg_qtd_t qtd,
dwc_otg_halt_status_e  halt_status 
) [static]
+
+
+ +

+Updates the state of an Isochronous URB when the transfer is stopped for any reason. +

+The fields of the current entry in the frame descriptor array are set based on the transfer state and the input _halt_status. Completes the Isochronous URB if all the URB frames have been completed.

+

Returns:
DWC_OTG_HC_XFER_COMPLETE if there are more frames remaining to be transferred in the URB. Otherwise return DWC_OTG_HC_XFER_URB_COMPLETE.
+ +

+Definition at line 626 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
static void deactivate_qh (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh,
int  free_qtd 
) [static]
+
+
+ +

+Frees the first QTD in the QH's list if free_qtd is 1. +

+For non-periodic QHs, removes the QH from the active non-periodic schedule. If any QTDs are still linked to the QH, the QH is added to the end of the inactive non-periodic schedule. For periodic QHs, removes the QH from the periodic schedule if no more QTDs are linked to the QH. +

+Definition at line 706 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static void release_channel (dwc_otg_hcd_t hcd,
dwc_hc_t hc,
dwc_otg_qtd_t qtd,
dwc_otg_halt_status_e  halt_status 
) [static]
+
+
+ +

+Releases a host channel for use by other transfers. +

+Attempts to select and queue more transactions since at least one host channel is available.

+

Parameters:
+ + + + + +
hcd The HCD state structure.
hc The host channel to release.
qtd The QTD associated with the host channel. This QTD may be freed if the transfer is complete or an error has occurred.
halt_status Reason the channel is being released. This status determines the actions taken by this function.
+
+ +

+Definition at line 742 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static void halt_channel (dwc_otg_hcd_t hcd,
dwc_hc_t hc,
dwc_otg_qtd_t qtd,
dwc_otg_halt_status_e  halt_status 
) [static]
+
+
+ +

+Halts a host channel. +

+If the channel cannot be halted immediately because the request queue is full, this function ensures that the FIFO empty interrupt for the appropriate queue is enabled so that the halt request can be queued when there is space in the request queue.

+This function may also be called in DMA mode. In that case, the channel is simply released since the core always halts the channel automatically in DMA mode. +

+Definition at line 833 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static void complete_non_periodic_xfer (dwc_otg_hcd_t hcd,
dwc_hc_t hc,
dwc_otg_hc_regs_t hc_regs,
dwc_otg_qtd_t qtd,
dwc_otg_halt_status_e  halt_status 
) [static]
+
+
+ +

+Performs common cleanup for non-periodic transfers after a Transfer Complete interrupt. +

+This function should be called after any endpoint type specific handling is finished to release the host channel. +

+Definition at line 885 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static void complete_periodic_xfer (dwc_otg_hcd_t hcd,
dwc_hc_t hc,
dwc_otg_hc_regs_t hc_regs,
dwc_otg_qtd_t qtd,
dwc_otg_halt_status_e  halt_status 
) [static]
+
+
+ +

+Performs common cleanup for periodic transfers after a Transfer Complete interrupt. +

+This function should be called after any endpoint type specific handling is finished to release the host channel. +

+Definition at line 937 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static int32_t handle_hc_xfercomp_intr (dwc_otg_hcd_t hcd,
dwc_hc_t hc,
dwc_otg_hc_regs_t hc_regs,
dwc_otg_qtd_t qtd 
) [static]
+
+
+ +

+Handles a host channel Transfer Complete interrupt. +

+This handler may be called in either DMA mode or Slave mode. +

+Definition at line 1002 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static int32_t handle_hc_stall_intr (dwc_otg_hcd_t hcd,
dwc_hc_t hc,
dwc_otg_hc_regs_t hc_regs,
dwc_otg_qtd_t qtd 
) [static]
+
+
+ +

+Handles a host channel STALL interrupt. +

+This handler may be called in either DMA mode or Slave mode. +

+Definition at line 1128 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static int32_t handle_hc_nak_intr (dwc_otg_hcd_t hcd,
dwc_hc_t hc,
dwc_otg_hc_regs_t hc_regs,
dwc_otg_qtd_t qtd 
) [static]
+
+
+ +

+Handles a host channel NAK interrupt. +

+This handler may be called in either DMA mode or Slave mode. +

+Definition at line 1214 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static int32_t handle_hc_ack_intr (dwc_otg_hcd_t hcd,
dwc_hc_t hc,
dwc_otg_hc_regs_t hc_regs,
dwc_otg_qtd_t qtd 
) [static]
+
+
+ +

+Handles a host channel ACK interrupt. +

+This interrupt is enabled when performing the PING protocol in Slave mode, when errors occur during either Slave mode or DMA mode, and during Start Split transactions. +

+Definition at line 1294 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static int32_t handle_hc_nyet_intr (dwc_otg_hcd_t hcd,
dwc_hc_t hc,
dwc_otg_hc_regs_t hc_regs,
dwc_otg_qtd_t qtd 
) [static]
+
+
+ +

+Handles a host channel NYET interrupt. +

+This interrupt should only occur on Bulk and Control OUT endpoints and for complete split transactions. If a NYET occurs at the same time as a Transfer Complete interrupt, it is handled in the xfercomp interrupt handler, not here. This handler may be called in either DMA mode or Slave mode. +

+

Todo:
add support for isoc release
+ +

+Definition at line 1388 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static int32_t handle_hc_babble_intr (dwc_otg_hcd_t hcd,
dwc_hc_t hc,
dwc_otg_hc_regs_t hc_regs,
dwc_otg_qtd_t qtd 
) [static]
+
+
+ +

+Handles a host channel babble interrupt. +

+This handler may be called in either DMA mode or Slave mode. +

+Definition at line 1466 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static int32_t handle_hc_ahberr_intr (dwc_otg_hcd_t hcd,
dwc_hc_t hc,
dwc_otg_hc_regs_t hc_regs,
dwc_otg_qtd_t qtd 
) [static]
+
+
+ +

+Handles a host channel AHB error interrupt. +

+This handler is only called in DMA mode. +

+Definition at line 1499 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static int32_t handle_hc_xacterr_intr (dwc_otg_hcd_t hcd,
dwc_hc_t hc,
dwc_otg_hc_regs_t hc_regs,
dwc_otg_qtd_t qtd 
) [static]
+
+
+ +

+Handles a host channel transaction error interrupt. +

+This handler may be called in either DMA mode or Slave mode. +

+Definition at line 1599 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static int32_t handle_hc_frmovrun_intr (dwc_otg_hcd_t hcd,
dwc_hc_t hc,
dwc_otg_hc_regs_t hc_regs,
dwc_otg_qtd_t qtd 
) [static]
+
+
+ +

+Handles a host channel frame overrun interrupt. +

+This handler may be called in either DMA mode or Slave mode. +

+Definition at line 1661 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static int32_t handle_hc_datatglerr_intr (dwc_otg_hcd_t hcd,
dwc_hc_t hc,
dwc_otg_hc_regs_t hc_regs,
dwc_otg_qtd_t qtd 
) [static]
+
+
+ +

+Handles a host channel data toggle error interrupt. +

+This handler may be called in either DMA mode or Slave mode. +

+Definition at line 1697 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static void handle_hc_chhltd_intr_dma (dwc_otg_hcd_t hcd,
dwc_hc_t hc,
dwc_otg_hc_regs_t hc_regs,
dwc_otg_qtd_t qtd 
) [static]
+
+
+ +

+Handles a host Channel Halted interrupt in DMA mode. +

+This handler determines the reason the channel halted and proceeds accordingly. +

+

Todo:
This is here because of a possible hardware bug. Spec says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT interrupt w/ACK bit set should occur, but I only see the XFERCOMP bit, even with it masked out. This is a workaround for that behavior. Should fix this when hardware is fixed.
+ +

+Definition at line 1784 of file dwc_otg_hcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static int32_t handle_hc_chhltd_intr (dwc_otg_hcd_t hcd,
dwc_hc_t hc,
dwc_otg_hc_regs_t hc_regs,
dwc_otg_qtd_t qtd 
) [static]
+
+
+ +

+Handles a host channel Channel Halted interrupt. +

+In slave mode, this handler is called only when the driver specifically requests a halt. This occurs during handling other host channel interrupts (e.g. nak, xacterr, stall, nyet, etc.).

+In DMA mode, this is the interrupt that occurs when the core has finished processing a transfer on a channel. Other host channel interrupts (except ahberr) are disabled in DMA mode. +

+Definition at line 1928 of file dwc_otg_hcd_intr.c. +

+

+


Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__linux_8c-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__linux_8c-source.html new file mode 100644 index 000000000000..cf20761d82b6 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__linux_8c-source.html @@ -0,0 +1,726 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hcd_linux.c Source File + + + + + + +

dwc_otg_hcd_linux.c

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_linux.c $
+00003  * $Revision: #11 $
+00004  * $Date: 2009/04/21 $
+00005  * $Change: 1237476 $
+00006  *
+00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009  * otherwise expressly agreed to in writing between Synopsys and you.
+00010  *
+00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012  * any End User Software License Agreement or Agreement for Licensed Product
+00013  * with Synopsys or any supplement thereto. You are permitted to use and
+00014  * redistribute this Software in source and binary forms, with or without
+00015  * modification, provided that redistributions of source code must retain this
+00016  * notice. You may not view, use, disclose, copy or distribute this file or
+00017  * any information contained herein except pursuant to this license grant from
+00018  * Synopsys. If you do not agree with this notice, including the disclaimer
+00019  * below, then you are not authorized to use the Software.
+00020  *
+00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031  * DAMAGE.
+00032  * ========================================================================== */
+00033 #ifndef DWC_DEVICE_ONLY
+00034 
+00041 #include <linux/kernel.h>
+00042 #include <linux/module.h>
+00043 #include <linux/moduleparam.h>
+00044 #include <linux/init.h>
+00045 #include <linux/device.h>
+00046 #include <linux/errno.h>
+00047 #include <linux/list.h>
+00048 #include <linux/interrupt.h>
+00049 #include <linux/string.h>
+00050 #include <linux/dma-mapping.h>
+00051 #include <linux/version.h>
+00052 #include <asm/io.h>
+00053 
+00054 #ifdef LM_INTERFACE
+00055 #include <asm/arch/regs-irq.h>
+00056 #include <asm/arch/lm.h>
+00057 #include <asm/arch/irqs.h>
+00058 #endif
+00059 
+00060 #include <linux/usb.h>
+00061 #include <../drivers/usb/core/hcd.h>
+00062 
+00063 #include "dwc_otg_hcd_if.h"
+00064 #include "dwc_otg_dbg.h"
+00065 #include "dwc_otg_driver.h"
+00066 
+00071 #define dwc_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \
+00072                                                      ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4)
+00073 
+00074 static const char dwc_otg_hcd_name[] = "dwc_otg_hcd";
+00075 
+00078 static int urb_enqueue(struct usb_hcd *hcd,
+00079                        struct usb_host_endpoint *ep,
+00080                        struct urb *urb, gfp_t mem_flags);
+00081 
+00082 static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
+00083 
+00084 static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
+00085 
+00086 static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd);
+00087 extern int hcd_start(struct usb_hcd *hcd);
+00088 extern void hcd_stop(struct usb_hcd *hcd);
+00089 static int get_frame_number(struct usb_hcd *hcd);
+00090 extern int hub_status_data(struct usb_hcd *hcd, char *buf);
+00091 extern int hub_control(struct usb_hcd *hcd,
+00092                        u16 typeReq,
+00093                        u16 wValue, u16 wIndex, char *buf, u16 wLength);
+00094 
+00095 struct wrapper_priv_data {
+00096         dwc_otg_hcd_t *dwc_otg_hcd;
+00097 };
+00098 
+00101 static struct hc_driver dwc_otg_hc_driver = {
+00102 
+00103         .description = dwc_otg_hcd_name,
+00104         .product_desc = "DWC OTG Controller",
+00105         .hcd_priv_size = sizeof(struct wrapper_priv_data),
+00106 
+00107         .irq = dwc_otg_hcd_irq,
+00108 
+00109         .flags = HCD_MEMORY | HCD_USB2,
+00110 
+00111         //.reset =              
+00112         .start = hcd_start,
+00113         //.suspend =            
+00114         //.resume =             
+00115         .stop = hcd_stop,
+00116 
+00117         .urb_enqueue = urb_enqueue,
+00118         .urb_dequeue = urb_dequeue,
+00119         .endpoint_disable = endpoint_disable,
+00120 
+00121         .get_frame_number = get_frame_number,
+00122 
+00123         .hub_status_data = hub_status_data,
+00124         .hub_control = hub_control,
+00125         //.bus_suspend =                
+00126         //.bus_resume =         
+00127 };
+00128 
+00130 static inline dwc_otg_hcd_t *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd)
+00131 {
+00132         struct wrapper_priv_data *p;
+00133         p = (struct wrapper_priv_data *)(hcd->hcd_priv);
+00134         return p->dwc_otg_hcd;
+00135 }
+00136 
+00138 static inline struct usb_hcd *dwc_otg_hcd_to_hcd(dwc_otg_hcd_t * dwc_otg_hcd)
+00139 {
+00140         return dwc_otg_hcd_get_priv_data(dwc_otg_hcd);
+00141 }
+00142 
+00144 inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb *urb)
+00145 {
+00146         struct usb_device *dev = urb->dev;
+00147         int ep_num = usb_pipeendpoint(urb->pipe);
+00148 
+00149         if (usb_pipein(urb->pipe))
+00150                 return dev->ep_in[ep_num];
+00151         else
+00152                 return dev->ep_out[ep_num];
+00153 }
+00154 
+00155 static int _disconnect(dwc_otg_hcd_t * hcd)
+00156 {
+00157         struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
+00158 
+00159         usb_hcd->self.is_b_host = 0;
+00160         return 0;
+00161 }
+00162 
+00163 static int _start(dwc_otg_hcd_t * hcd)
+00164 {
+00165         struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
+00166 
+00167         usb_hcd->self.is_b_host = dwc_otg_hcd_is_b_host(hcd);
+00168         hcd_start(usb_hcd);
+00169 
+00170         return 0;
+00171 }
+00172 
+00173 static int _hub_info(dwc_otg_hcd_t * hcd, void *urb_handle, uint32_t * hub_addr,
+00174                      uint32_t * port_addr)
+00175 {
+00176         struct urb *urb = (struct urb *)urb_handle;
+00177         if (urb->dev->tt) {
+00178                 *hub_addr = urb->dev->tt->hub->devnum;
+00179         } else {
+00180                 *hub_addr = 0;
+00181         }
+00182         *port_addr = urb->dev->ttport;
+00183         return 0;
+00184 }
+00185 
+00186 static int _speed(dwc_otg_hcd_t * hcd, void *urb_handle)
+00187 {
+00188         struct urb *urb = (struct urb *)urb_handle;
+00189         return urb->dev->speed;
+00190 }
+00191 
+00192 static int _get_b_hnp_enable(dwc_otg_hcd_t * hcd)
+00193 {
+00194         struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd);
+00195         return usb_hcd->self.b_hnp_enable;
+00196 }
+00197 
+00198 static void allocate_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
+00199                                    struct urb *urb)
+00200 {
+00201         hcd_to_bus(hcd)->bandwidth_allocated += bw / urb->interval;
+00202         if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+00203                 hcd_to_bus(hcd)->bandwidth_isoc_reqs++;
+00204         } else {
+00205                 hcd_to_bus(hcd)->bandwidth_int_reqs++;
+00206         }
+00207 }
+00208 
+00209 static void free_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
+00210                                struct urb *urb)
+00211 {
+00212         hcd_to_bus(hcd)->bandwidth_allocated -= bw / urb->interval;
+00213         if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+00214                 hcd_to_bus(hcd)->bandwidth_isoc_reqs--;
+00215         } else {
+00216                 hcd_to_bus(hcd)->bandwidth_int_reqs--;
+00217         }
+00218 }
+00219 
+00224 static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
+00225                      dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status)
+00226 {
+00227         struct urb *urb = (struct urb *)urb_handle;
+00228 #ifdef DEBUG
+00229         if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
+00230                 DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n",
+00231                            __func__, urb, usb_pipedevice(urb->pipe),
+00232                            usb_pipeendpoint(urb->pipe),
+00233                            usb_pipein(urb->pipe) ? "IN" : "OUT", status);
+00234                 if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+00235                         int i;
+00236                         for (i = 0; i < urb->number_of_packets; i++) {
+00237                                 DWC_PRINTF("  ISO Desc %d status: %d\n",
+00238                                            i, urb->iso_frame_desc[i].status);
+00239                         }
+00240                 }
+00241         }
+00242 #endif
+00243 
+00244         urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb);
+00245         /* Convert status value. */
+00246         switch (status) {
+00247         case -DWC_E_PROTOCOL:
+00248                 status = -EPROTO;
+00249                 break;
+00250         case -DWC_E_IN_PROGRESS:
+00251                 status = -EINPROGRESS;
+00252                 break;
+00253         case -DWC_E_PIPE:
+00254                 status = -EPIPE;
+00255                 break;
+00256         case -DWC_E_IO:
+00257                 status = -EIO;
+00258                 break;
+00259         case -DWC_E_TIMEOUT:
+00260                 status = -ETIMEDOUT;
+00261                 break;
+00262         case -DWC_E_OVERFLOW:
+00263                 status = -EOVERFLOW;
+00264                 break;
+00265         default:
+00266                 if (status) {
+00267                         DWC_PRINTF("Uknown urb status %d\n", status);
+00268 
+00269                 }
+00270         }
+00271 
+00272         if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+00273                 int i;
+00274 
+00275                 urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb);
+00276                 for (i = 0; i < urb->number_of_packets; ++i) {
+00277                         urb->iso_frame_desc[i].actual_length =
+00278                             dwc_otg_hcd_urb_get_iso_desc_actual_length
+00279                             (dwc_otg_urb, i);
+00280                         urb->iso_frame_desc[i].status =
+00281                             dwc_otg_hcd_urb_get_iso_desc_status
+00282                             (dwc_otg_urb, i);
+00283                 }
+00284         }
+00285 
+00286         urb->status = status;
+00287         urb->hcpriv = NULL;
+00288         if (!status) {
+00289                 if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+00290                     (urb->actual_length < urb->transfer_buffer_length)) {
+00291                         urb->status = -EREMOTEIO;
+00292                 }
+00293         }
+00294 
+00295         if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) ||
+00296             (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
+00297                 struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb);
+00298                 if (ep) {
+00299                         free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd),
+00300                                            dwc_otg_hcd_get_ep_bandwidth(hcd,
+00301                                                                         ep->
+00302                                                                         hcpriv),
+00303                                            urb);
+00304                 }
+00305         }
+00306 
+00307         dwc_free(dwc_otg_urb);
+00308         usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb);
+00309         return 0;
+00310 }
+00311 
+00312 static struct dwc_otg_hcd_function_ops hcd_fops = {
+00313         .start = _start,
+00314         .disconnect = _disconnect,
+00315         .hub_info = _hub_info,
+00316         .speed = _speed,
+00317         .complete = _complete,
+00318         .get_b_hnp_enable = _get_b_hnp_enable,
+00319 };
+00320 
+00327 int hcd_init(
+00328 #ifdef LM_INTERFACE
+00329         struct lm_device *_dev
+00330 #elif  PCI_INTERFACE
+00331         struct pci_dev *_dev
+00332 #endif
+00333         )
+00334 {
+00335         struct usb_hcd *hcd = NULL;
+00336         dwc_otg_hcd_t *dwc_otg_hcd = NULL;
+00337 #ifdef LM_INTERFACE
+00338         dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
+00339 #elif  PCI_INTERFACE
+00340         dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
+00341 #endif
+00342 
+00343         int retval = 0;
+00344 
+00345         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT\n");
+00346 
+00347         /* Set device flags indicating whether the HCD supports DMA. */
+00348         if (dwc_otg_is_dma_enable(otg_dev->core_if)) {
+00349 #ifdef LM_INTERFACE
+00350                 _dev->dev.dma_mask = (void *)~0;
+00351                 _dev->dev.coherent_dma_mask = ~0;
+00352 #elif  PCI_INTERFACE
+00353                 pci_set_dma_mask(_dev,DMA_32BIT_MASK);          
+00354                 pci_set_consistent_dma_mask(_dev,DMA_32BIT_MASK);
+00355 #endif
+00356 
+00357         } else {
+00358 #ifdef LM_INTERFACE
+00359                 _dev->dev.dma_mask = (void *)0;
+00360                 _dev->dev.coherent_dma_mask = 0;
+00361 #elif  PCI_INTERFACE
+00362                 pci_set_dma_mask(_dev,0);               
+00363                 pci_set_consistent_dma_mask(_dev,0);
+00364 #endif
+00365         }
+00366 
+00367         /*
+00368          * Allocate memory for the base HCD plus the DWC OTG HCD.
+00369          * Initialize the base HCD.
+00370          */
+00371         hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, _dev->dev.bus_id);
+00372         if (!hcd) {
+00373                 retval = -ENOMEM;
+00374                 goto error1;
+00375         }
+00376 
+00377         hcd->regs = otg_dev->base;
+00378 
+00379         /* Initialize the DWC OTG HCD. */
+00380         dwc_otg_hcd = dwc_otg_hcd_alloc_hcd();
+00381         if (!dwc_otg_hcd) {
+00382                 goto error2;
+00383         }
+00384         ((struct wrapper_priv_data *)(hcd->hcd_priv))->dwc_otg_hcd =
+00385             dwc_otg_hcd;
+00386         otg_dev->hcd = dwc_otg_hcd;
+00387 
+00388         if (dwc_otg_hcd_init(dwc_otg_hcd, otg_dev->core_if)) {
+00389                 goto error2;
+00390         }
+00391 
+00392         hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd);
+00393 
+00394         /*
+00395          * Finish generic HCD initialization and start the HCD. This function
+00396          * allocates the DMA buffer pool, registers the USB bus, requests the
+00397          * IRQ line, and calls hcd_start method.
+00398          */
+00399         retval = usb_add_hcd(hcd, _dev->irq, SA_SHIRQ);
+00400         if (retval < 0) {
+00401                 goto error2;
+00402         }
+00403 
+00404         dwc_otg_hcd_set_priv_data(dwc_otg_hcd, hcd);
+00405         return 0;
+00406 
+00407       error2:
+00408         usb_put_hcd(hcd);
+00409       error1:
+00410         return retval;
+00411 }
+00412 
+00417 void hcd_remove(
+00418 #ifdef LM_INTERFACE
+00419         struct lm_device *_dev
+00420 #elif  PCI_INTERFACE
+00421         struct pci_dev *_dev
+00422 #endif
+00423         )
+00424 {
+00425 #ifdef LM_INTERFACE
+00426         dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
+00427 #elif  PCI_INTERFACE
+00428         dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
+00429 #endif
+00430 
+00431         dwc_otg_hcd_t *dwc_otg_hcd;
+00432         struct usb_hcd *hcd;
+00433 
+00434         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE\n");
+00435 
+00436         if (!otg_dev) {
+00437                 DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__);
+00438                 return;
+00439         }
+00440 
+00441         dwc_otg_hcd = otg_dev->hcd;
+00442 
+00443         if (!dwc_otg_hcd) {
+00444                 DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__);
+00445                 return;
+00446         }
+00447 
+00448         hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd);
+00449 
+00450         if (!hcd) {
+00451                 DWC_DEBUGPL(DBG_ANY,
+00452                             "%s: dwc_otg_hcd_to_hcd(dwc_otg_hcd) NULL!\n",
+00453                             __func__);
+00454                 return;
+00455         }
+00456         usb_remove_hcd(hcd);
+00457         dwc_otg_hcd_set_priv_data(dwc_otg_hcd, NULL);
+00458         dwc_otg_hcd_remove(dwc_otg_hcd);
+00459         usb_put_hcd(hcd);
+00460 }
+00461 
+00462 /* =========================================================================
+00463  *  Linux HC Driver Functions
+00464  * ========================================================================= */
+00465 
+00469 int hcd_start(struct usb_hcd *hcd)
+00470 {
+00471         dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+00472         struct usb_bus *bus;
+00473 
+00474         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n");
+00475         bus = hcd_to_bus(hcd);
+00476 
+00477         hcd->state = HC_STATE_RUNNING;
+00478         if (dwc_otg_hcd_start(dwc_otg_hcd, &hcd_fops)) {
+00479                 return 0;
+00480         }
+00481 
+00482         /* Initialize and connect root hub if one is not already attached */
+00483         if (bus->root_hub) {
+00484                 DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n");
+00485                 /* Inform the HUB driver to resume. */
+00486                 usb_hcd_resume_root_hub(hcd);
+00487         }
+00488 
+00489         return 0;
+00490 }
+00491 
+00496 void hcd_stop(struct usb_hcd *hcd)
+00497 {
+00498         dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+00499 
+00500         dwc_otg_hcd_stop(dwc_otg_hcd);
+00501 }
+00502 
+00504 static int get_frame_number(struct usb_hcd *hcd)
+00505 {
+00506         dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+00507 
+00508         return dwc_otg_hcd_get_frame_number(dwc_otg_hcd);
+00509 }
+00510 
+00511 #ifdef DEBUG
+00512 static void dump_urb_info(struct urb *urb, char *fn_name)
+00513 {
+00514         DWC_PRINTF("%s, urb %p\n", fn_name, urb);
+00515         DWC_PRINTF("  Device address: %d\n", usb_pipedevice(urb->pipe));
+00516         DWC_PRINTF("  Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe),
+00517                    (usb_pipein(urb->pipe) ? "IN" : "OUT"));
+00518         DWC_PRINTF("  Endpoint type: %s\n", ( {
+00519                                              char *pipetype;
+00520                                              switch (usb_pipetype(urb->pipe)) {
+00521 case PIPE_CONTROL:
+00522 pipetype = "CONTROL"; break; case PIPE_BULK:
+00523 pipetype = "BULK"; break; case PIPE_INTERRUPT:
+00524 pipetype = "INTERRUPT"; break; case PIPE_ISOCHRONOUS:
+00525 pipetype = "ISOCHRONOUS"; break; default:
+00526                                              pipetype = "UNKNOWN"; break;};
+00527                                              pipetype;}
+00528                    )) ;
+00529         DWC_PRINTF("  Speed: %s\n", ( {
+00530                                      char *speed; switch (urb->dev->speed) {
+00531 case USB_SPEED_HIGH:
+00532 speed = "HIGH"; break; case USB_SPEED_FULL:
+00533 speed = "FULL"; break; case USB_SPEED_LOW:
+00534 speed = "LOW"; break; default:
+00535                                      speed = "UNKNOWN"; break;};
+00536                                      speed;}
+00537                    )) ;
+00538         DWC_PRINTF("  Max packet size: %d\n",
+00539                    usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
+00540         DWC_PRINTF("  Data buffer length: %d\n", urb->transfer_buffer_length);
+00541         DWC_PRINTF("  Transfer buffer: %p, Transfer DMA: %p\n",
+00542                    urb->transfer_buffer, (void *)urb->transfer_dma);
+00543         DWC_PRINTF("  Setup buffer: %p, Setup DMA: %p\n",
+00544                    urb->setup_packet, (void *)urb->setup_dma);
+00545         DWC_PRINTF("  Interval: %d\n", urb->interval);
+00546         if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+00547                 int i;
+00548                 for (i = 0; i < urb->number_of_packets; i++) {
+00549                         DWC_PRINTF("  ISO Desc %d:\n", i);
+00550                         DWC_PRINTF("    offset: %d, length %d\n",
+00551                                    urb->iso_frame_desc[i].offset,
+00552                                    urb->iso_frame_desc[i].length);
+00553                 }
+00554         }
+00555 }
+00556 
+00557 #endif
+00558 
+00562 static int urb_enqueue(struct usb_hcd *hcd,
+00563                        struct usb_host_endpoint *ep,
+00564                        struct urb *urb, gfp_t mem_flags)
+00565 {
+00566         int retval = 0;
+00567         dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+00568         dwc_otg_hcd_urb_t *dwc_otg_urb;
+00569         int i;
+00570         int alloc_bandwidth = 0;
+00571         uint8_t ep_type = 0;
+00572         uint32_t flags = 0;
+00573         void *buf;
+00574 
+00575 #ifdef DEBUG
+00576         if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
+00577                 dump_urb_info(urb, "urb_enqueue");
+00578         }
+00579 #endif
+00580 
+00581         if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
+00582             || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
+00583                 if (!dwc_otg_hcd_is_bandwidth_allocated
+00584                     (dwc_otg_hcd, &ep->hcpriv)) {
+00585                         alloc_bandwidth = 1;
+00586                 }
+00587         }
+00588 
+00589         switch (usb_pipetype(urb->pipe)) {
+00590         case PIPE_CONTROL:
+00591                 ep_type = USB_ENDPOINT_XFER_CONTROL;
+00592                 break;
+00593         case PIPE_ISOCHRONOUS:
+00594                 ep_type = USB_ENDPOINT_XFER_ISOC;
+00595                 break;
+00596         case PIPE_BULK:
+00597                 ep_type = USB_ENDPOINT_XFER_BULK;
+00598                 break;
+00599         case PIPE_INTERRUPT:
+00600                 ep_type = USB_ENDPOINT_XFER_INT;
+00601                 break;
+00602         default:
+00603                 DWC_WARN("Wrong ep type\n");
+00604         }
+00605 
+00606         dwc_otg_urb = dwc_otg_hcd_urb_alloc(dwc_otg_hcd,
+00607                                             urb->number_of_packets,
+00608                                             mem_flags == GFP_ATOMIC ? 1 : 0);
+00609 
+00610         dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe),
+00611                                      usb_pipeendpoint(urb->pipe), ep_type,
+00612                                      usb_pipein(urb->pipe),
+00613                                      usb_maxpacket(urb->dev, urb->pipe,
+00614                                                    !(usb_pipein(urb->pipe))));
+00615 
+00616         buf = urb->transfer_buffer;
+00617         if (hcd->self.uses_dma) {
+00618                 /*
+00619                  * Calculate virtual address from physical address,
+00620                  * because some class driver may not fill transfer_buffer.
+00621                  * In Buffer DMA mode virual address is used,
+00622                  * when handling non DWORD aligned buffers.
+00623                  */
+00624                 buf = phys_to_virt(urb->transfer_dma);
+00625         }
+00626         
+00627         if (!(urb->transfer_flags & URB_NO_INTERRUPT))
+00628                 flags |= URB_GIVEBACK_ASAP;
+00629         if (urb->transfer_flags & URB_ZERO_PACKET)
+00630                 flags |= URB_SEND_ZERO_PACKET;
+00631 
+00632         dwc_otg_hcd_urb_set_params(dwc_otg_urb, urb, buf,
+00633                                    urb->transfer_dma,
+00634                                    urb->transfer_buffer_length,
+00635                                    urb->setup_packet, 
+00636                                    urb->setup_dma,
+00637                                    flags,
+00638                                    urb->interval);
+00639 
+00640         for (i = 0; i < urb->number_of_packets; ++i) {
+00641                 dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_urb, i,
+00642                                                     urb->iso_frame_desc[i].
+00643                                                     offset,
+00644                                                     urb->iso_frame_desc[i].
+00645                                                     length);
+00646         }
+00647 
+00648         urb->hcpriv = dwc_otg_urb;
+00649         retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb, &ep->hcpriv);
+00650         if (!retval) {
+00651                 if (alloc_bandwidth) {
+00652                         allocate_bus_bandwidth(hcd,
+00653                                                dwc_otg_hcd_get_ep_bandwidth
+00654                                                (dwc_otg_hcd, ep->hcpriv), urb);
+00655                 }
+00656         } else {
+00657                 if (retval == -DWC_E_NO_DEVICE) {
+00658                         retval = -ENODEV;
+00659                 }
+00660         }
+00661 
+00662         return retval;
+00663 }
+00664 
+00667 static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+00668 {
+00669         dwc_otg_hcd_t *dwc_otg_hcd;
+00670         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n");
+00671 
+00672         dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+00673 
+00674 #ifdef DEBUG
+00675         if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
+00676                 dump_urb_info(urb, "urb_dequeue");
+00677         }
+00678 #endif
+00679         dwc_otg_hcd_urb_dequeue(dwc_otg_hcd, urb->hcpriv);
+00680 
+00681         dwc_free(urb->hcpriv);
+00682         urb->hcpriv = NULL;
+00683 
+00684         /* Higher layer software sets URB status. */
+00685         usb_hcd_giveback_urb(hcd, urb);
+00686         if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
+00687                 DWC_PRINTF("Called usb_hcd_giveback_urb()\n");
+00688                 DWC_PRINTF("  urb->status = %d\n", urb->status);
+00689         }
+00690 
+00691         return 0;
+00692 }
+00693 
+00694 /* Frees resources in the DWC_otg controller related to a given endpoint. Also
+00695  * clears state in the HCD related to the endpoint. Any URBs for the endpoint
+00696  * must already be dequeued. */
+00697 static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+00698 {
+00699         dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+00700 
+00701         DWC_DEBUGPL(DBG_HCD,
+00702                     "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, "
+00703                     "endpoint=%d\n", ep->desc.bEndpointAddress,
+00704                     dwc_ep_addr_to_endpoint(ep->desc.bEndpointAddress));
+00705         dwc_otg_hcd_endpoint_disable(dwc_otg_hcd, ep->hcpriv, 250);
+00706         ep->hcpriv = NULL;
+00707 }
+00708 
+00714 static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd)
+00715 {
+00716         dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+00717         int32_t retval = dwc_otg_hcd_handle_intr(dwc_otg_hcd);
+00718         if (retval != 0) {
+00719                 S3C2410X_CLEAR_EINTPEND();
+00720         }
+00721         return IRQ_RETVAL(retval);
+00722 }
+00723 
+00728 int hub_status_data(struct usb_hcd *hcd, char *buf)
+00729 {
+00730         dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+00731 
+00732         buf[0] = 0;
+00733         buf[0] |= (dwc_otg_hcd_is_status_changed(dwc_otg_hcd, 1)) << 1;
+00734 
+00735         return (buf[0] != 0);
+00736 }
+00737 
+00739 int hub_control(struct usb_hcd *hcd,
+00740                 u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
+00741 {
+00742         int retval;
+00743 
+00744         retval = dwc_otg_hcd_hub_control(hcd_to_dwc_otg_hcd(hcd),
+00745                                          typeReq, wValue, wIndex, buf, wLength);
+00746 
+00747         switch (retval) {
+00748         case -DWC_E_INVALID:
+00749                 retval = -EINVAL;
+00750                 break;
+00751         }
+00752 
+00753         return retval;
+00754 }
+00755 
+00756 #endif                          /* DWC_DEVICE_ONLY */
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__linux_8c.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__linux_8c.html new file mode 100644 index 000000000000..e88d9714dcac --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__linux_8c.html @@ -0,0 +1,514 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hcd_linux.c File Reference + + + + + + +

dwc_otg_hcd_linux.c File Reference

This file contains the implementation of the HCD. More... +

+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/dma-mapping.h>
+#include <linux/version.h>
+#include <asm/io.h>
+#include <linux/usb.h>
+#include <../drivers/usb/core/hcd.h>
+#include "dwc_otg_hcd_if.h"
+#include "dwc_otg_dbg.h"
+#include "dwc_otg_driver.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Structures

struct  wrapper_priv_data

Linux HC Driver API Functions

static int urb_enqueue (struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct urb *urb, gfp_t mem_flags)
 Starts processing a USB transfer request specified by a USB Request Block (URB).
static int urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
 Aborts/cancels a USB transfer request.
+static void endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep)
static irqreturn_t dwc_otg_hcd_irq (struct usb_hcd *hcd)
 Handles host mode interrupts for the DWC_otg controller.
int hcd_start (struct usb_hcd *hcd)
 Initializes the DWC_otg controller and its root hub and prepares it for host mode operation.
void hcd_stop (struct usb_hcd *hcd)
 Halts the DWC_otg host mode operations in a clean manner.
+static int get_frame_number (struct usb_hcd *hcd)
 Returns the current frame number.
int hub_status_data (struct usb_hcd *hcd, char *buf)
 Creates Status Change bitmap for the root hub and root port.
+int hub_control (struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
 Handles hub class-specific requests.

Defines

#define dwc_ep_addr_to_endpoint(_bEndpointAddress_)
 Gets the endpoint number from a _bEndpointAddress argument.

Functions

+static dwc_otg_hcd_thcd_to_dwc_otg_hcd (struct usb_hcd *hcd)
 Gets the dwc_otg_hcd from a struct usb_hcd.
+static struct usb_hcd * dwc_otg_hcd_to_hcd (dwc_otg_hcd_t *dwc_otg_hcd)
 Gets the struct usb_hcd that contains a dwc_otg_hcd_t.
+usb_host_endpoint * dwc_urb_to_endpoint (struct urb *urb)
 Gets the usb_host_endpoint associated with an URB.
+static int _disconnect (dwc_otg_hcd_t *hcd)
+static int _start (dwc_otg_hcd_t *hcd)
+static int _hub_info (dwc_otg_hcd_t *hcd, void *urb_handle, uint32_t *hub_addr, uint32_t *port_addr)
+static int _speed (dwc_otg_hcd_t *hcd, void *urb_handle)
+static int _get_b_hnp_enable (dwc_otg_hcd_t *hcd)
+static void allocate_bus_bandwidth (struct usb_hcd *hcd, uint32_t bw, struct urb *urb)
+static void free_bus_bandwidth (struct usb_hcd *hcd, uint32_t bw, struct urb *urb)
static int _complete (dwc_otg_hcd_t *hcd, void *urb_handle, dwc_otg_hcd_urb_t *dwc_otg_urb, int32_t status)
 Sets the final status of an URB and returns it to the device driver.
int hcd_init ()
 Initializes the HCD.
void hcd_remove ()
 Removes the HCD.

Variables

+static const char dwc_otg_hcd_name [] = "dwc_otg_hcd"
static struct hc_driver dwc_otg_hc_driver
static struct dwc_otg_hcd_function_ops hcd_fops
+


Detailed Description

+This file contains the implementation of the HCD. +

+In Linux, the HCD implements the hc_driver API. +

+Definition in file dwc_otg_hcd_linux.c.


Define Documentation

+ +
+
+ + + + + + + + + +
#define dwc_ep_addr_to_endpoint (_bEndpointAddress_   ) 
+
+
+ +

+Value:

((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \
+                                                     ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4)
+
Gets the endpoint number from a _bEndpointAddress argument. +

+The endpoint is qualified with its direction (possible 32 endpoints per device). +

+Definition at line 71 of file dwc_otg_hcd_linux.c. +

+

+


Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static int urb_enqueue (struct usb_hcd *  hcd,
struct usb_host_endpoint *  ep,
struct urb *  urb,
gfp_t  mem_flags 
) [static]
+
+
+ +

+Starts processing a USB transfer request specified by a USB Request Block (URB). +

+mem_flags indicates the type of memory allocation to use while processing this URB. +

+Definition at line 562 of file dwc_otg_hcd_linux.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static int urb_dequeue (struct usb_hcd *  hcd,
struct urb *  urb 
) [static]
+
+
+ +

+Aborts/cancels a USB transfer request. +

+Always returns 0 to indicate success. +

+Definition at line 667 of file dwc_otg_hcd_linux.c. +

+

+ +

+
+ + + + + + + + + +
static irqreturn_t dwc_otg_hcd_irq (struct usb_hcd *  hcd  )  [static]
+
+
+ +

+Handles host mode interrupts for the DWC_otg controller. +

+Returns IRQ_NONE if there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid interrupt.

+This function is called by the USB core when an interrupt occurs +

+Definition at line 714 of file dwc_otg_hcd_linux.c. +

+

+ +

+
+ + + + + + + + + +
int hcd_start (struct usb_hcd *  hcd  ) 
+
+
+ +

+Initializes the DWC_otg controller and its root hub and prepares it for host mode operation. +

+Activates the root port. Returns 0 on success and a negative error code on failure. +

+Definition at line 469 of file dwc_otg_hcd_linux.c. +

+

+ +

+
+ + + + + + + + + +
void hcd_stop (struct usb_hcd *  hcd  ) 
+
+
+ +

+Halts the DWC_otg host mode operations in a clean manner. +

+USB transfers are stopped. +

+Definition at line 496 of file dwc_otg_hcd_linux.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int hub_status_data (struct usb_hcd *  hcd,
char *  buf 
)
+
+
+ +

+Creates Status Change bitmap for the root hub and root port. +

+The bitmap is returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1 is the status change indicator for the single root port. Returns 1 if either change indicator is 1, otherwise returns 0. +

+Definition at line 728 of file dwc_otg_hcd_linux.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static int _complete (dwc_otg_hcd_t hcd,
void *  urb_handle,
dwc_otg_hcd_urb_t dwc_otg_urb,
int32_t  status 
) [static]
+
+
+ +

+Sets the final status of an URB and returns it to the device driver. +

+Any required cleanup of the URB is performed. +

+Definition at line 224 of file dwc_otg_hcd_linux.c. +

+

+ +

+
+ + + + + + + + +
int hcd_init (  ) 
+
+
+ +

+Initializes the HCD. +

+This function allocates memory for and initializes the static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the USB bus with the core and calls the hc_driver->start() function. It returns a negative error on failure. +

+Definition at line 327 of file dwc_otg_hcd_linux.c. +

+

+ +

+
+ + + + + + + + +
void hcd_remove (  ) 
+
+
+ +

+Removes the HCD. +

+Frees memory and resources associated with the HCD and deregisters the bus. +

+Definition at line 417 of file dwc_otg_hcd_linux.c. +

+

+


Variable Documentation

+ +
+
+ + + + +
struct hc_driver dwc_otg_hc_driver [static]
+
+
+ +

+Initial value:

 {
+
+        .description = dwc_otg_hcd_name,
+        .product_desc = "DWC OTG Controller",
+        .hcd_priv_size = sizeof(struct wrapper_priv_data),
+
+        .irq = dwc_otg_hcd_irq,
+
+        .flags = HCD_MEMORY | HCD_USB2,
+
+        
+        .start = hcd_start,
+        
+        
+        .stop = hcd_stop,
+
+        .urb_enqueue = urb_enqueue,
+        .urb_dequeue = urb_dequeue,
+        .endpoint_disable = endpoint_disable,
+
+        .get_frame_number = get_frame_number,
+
+        .hub_status_data = hub_status_data,
+        .hub_control = hub_control,
+        
+        
+}
+
+

+Definition at line 101 of file dwc_otg_hcd_linux.c. +

+

+ +

+
+ + + + +
struct dwc_otg_hcd_function_ops hcd_fops [static]
+
+
+ +

+Initial value:

 {
+        .start = _start,
+        .disconnect = _disconnect,
+        .hub_info = _hub_info,
+        .speed = _speed,
+        .complete = _complete,
+        .get_b_hnp_enable = _get_b_hnp_enable,
+}
+
+

+Definition at line 312 of file dwc_otg_hcd_linux.c. +

+

+


Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__queue_8c-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__queue_8c-source.html new file mode 100644 index 000000000000..f6d0b56f75f2 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__queue_8c-source.html @@ -0,0 +1,633 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hcd_queue.c Source File + + + + + + +

dwc_otg_hcd_queue.c

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_queue.c $
+00003  * $Revision: #39 $
+00004  * $Date: 2009/04/21 $
+00005  * $Change: 1237477 $
+00006  *
+00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009  * otherwise expressly agreed to in writing between Synopsys and you.
+00010  * 
+00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012  * any End User Software License Agreement or Agreement for Licensed Product
+00013  * with Synopsys or any supplement thereto. You are permitted to use and
+00014  * redistribute this Software in source and binary forms, with or without
+00015  * modification, provided that redistributions of source code must retain this
+00016  * notice. You may not view, use, disclose, copy or distribute this file or
+00017  * any information contained herein except pursuant to this license grant from
+00018  * Synopsys. If you do not agree with this notice, including the disclaimer
+00019  * below, then you are not authorized to use the Software.
+00020  * 
+00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031  * DAMAGE.
+00032  * ========================================================================== */
+00033 #ifndef DWC_DEVICE_ONLY
+00034 
+00042 #include "dwc_otg_hcd.h"
+00043 #include "dwc_otg_regs.h"
+00044 
+00053 void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+00054 {
+00055         dwc_otg_qtd_t *qtd, *qtd_tmp;
+00056         uint64_t flags;
+00057 
+00058         /* Free each QTD in the QTD list */
+00059         DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
+00060         DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
+00061                 DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry);
+00062                 dwc_otg_hcd_qtd_free(qtd);
+00063         }
+00064         DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
+00065 
+00066         if (hcd->core_if->dma_desc_enable) {
+00067                 dwc_otg_hcd_qh_free_ddma(hcd, qh);
+00068         }
+00069         else if (qh->dw_align_buf) {
+00070                 uint32_t buf_size;
+00071                 if(qh->ep_type == UE_ISOCHRONOUS) {
+00072                         buf_size = 4096;
+00073                 } else {
+00074                         buf_size = hcd->core_if->core_params->max_transfer_size;
+00075                 }
+00076                 dwc_dma_free(buf_size, qh->dw_align_buf, qh->dw_align_buf_dma);
+00077         }
+00078         
+00079         
+00080         
+00081         dwc_free(qh);
+00082         return;
+00083 }
+00084 
+00085 #define BitStuffTime(bytecount)  ((8 * 7* bytecount) / 6)
+00086 #define HS_HOST_DELAY           5       /* nanoseconds */
+00087 #define FS_LS_HOST_DELAY        1000    /* nanoseconds */
+00088 #define HUB_LS_SETUP            333     /* nanoseconds */
+00089 #define NS_TO_US(ns)            ((ns + 500) / 1000)
+00090                                 /* convert & round nanoseconds to microseconds */
+00091 
+00092 static uint32_t calc_bus_time(int speed, int is_in, int is_isoc,
+00093                                           int bytecount)
+00094 {
+00095         unsigned long retval;
+00096 
+00097         switch (speed) {
+00098         case USB_SPEED_HIGH:
+00099                 if (is_isoc) {
+00100                         retval =
+00101                             ((38 * 8 * 2083) +
+00102                              (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
+00103                             HS_HOST_DELAY;
+00104                 } else {
+00105                         retval =
+00106                             ((55 * 8 * 2083) +
+00107                              (2083 * (3 + BitStuffTime(bytecount)))) / 1000 +
+00108                             HS_HOST_DELAY;
+00109                 }
+00110                 break;
+00111         case USB_SPEED_FULL:
+00112                 if (is_isoc) {
+00113                         retval =
+00114                             (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
+00115                         if (is_in) {
+00116                                 retval = 7268 + FS_LS_HOST_DELAY + retval;
+00117                         } else {
+00118                                 retval = 6265 + FS_LS_HOST_DELAY + retval;
+00119                         }
+00120                 } else {
+00121                         retval =
+00122                             (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000;
+00123                         retval = 9107 + FS_LS_HOST_DELAY + retval;
+00124                 }
+00125                 break;
+00126         case USB_SPEED_LOW:
+00127                 if (is_in) {
+00128                         retval =
+00129                             (67667 * (31 + 10 * BitStuffTime(bytecount))) /
+00130                             1000;
+00131                         retval =
+00132                             64060 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
+00133                             retval;
+00134                 } else {
+00135                         retval =
+00136                             (66700 * (31 + 10 * BitStuffTime(bytecount))) /
+00137                             1000;
+00138                         retval =
+00139                             64107 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY +
+00140                             retval;
+00141                 }
+00142                 break;
+00143         default:
+00144                 DWC_WARN("Unknown device speed\n");
+00145                 retval = -1;
+00146         }
+00147         
+00148         return NS_TO_US(retval);
+00149 }
+00150 
+00159 #define SCHEDULE_SLOP 10
+00160 void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
+00161                          dwc_otg_hcd_urb_t * urb)
+00162 {
+00163         char *speed, *type;
+00164         int dev_speed;
+00165         uint32_t hub_addr, hub_port;
+00166 
+00167         dwc_memset(qh, 0, sizeof(dwc_otg_qh_t));
+00168         
+00169         /* Initialize QH */
+00170         qh->ep_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info);
+00171 
+00172         qh->ep_is_in = dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0;
+00173 
+00174         qh->data_toggle = DWC_OTG_HC_PID_DATA0;
+00175         qh->maxp = dwc_otg_hcd_get_mps(&urb->pipe_info);
+00176         DWC_CIRCLEQ_INIT(&qh->qtd_list);
+00177         DWC_LIST_INIT(&qh->qh_list_entry);
+00178         qh->channel = NULL;
+00179 
+00180         /* FS/LS Enpoint on HS Hub 
+00181          * NOT virtual root hub */
+00182         dev_speed = hcd->fops->speed(hcd, urb->priv);
+00183         hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &hub_port);
+00184         qh->do_split = 0;
+00185         if (((dev_speed == USB_SPEED_LOW) ||
+00186              (dev_speed == USB_SPEED_FULL)) &&
+00187             (hub_addr != 0 && hub_addr != 1)) {
+00188                 
+00189                 DWC_DEBUGPL(DBG_HCD,
+00190                             "QH init: EP %d: TT found at hub addr %d, for port %d\n",
+00191                             dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr,
+00192                             hub_port);
+00193                 
+00194                 qh->do_split = 1;
+00195         }
+00196 
+00197         if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) {
+00198                 /* Compute scheduling parameters once and save them. */
+00199                 hprt0_data_t hprt;
+00200 
+00202                 int bytecount =
+00203                     dwc_hb_mult(qh->maxp) * dwc_max_packet(qh->maxp);
+00204 
+00205                 qh->usecs = calc_bus_time((qh->do_split ? USB_SPEED_HIGH : dev_speed),
+00206                                           qh->ep_is_in,
+00207                                           (qh->ep_type == UE_ISOCHRONOUS),
+00208                                           bytecount);
+00209                 /* Start in a slightly future (micro)frame. */
+00210                 qh->sched_frame = dwc_frame_num_inc(hcd->frame_number,
+00211                                                     SCHEDULE_SLOP);
+00212                 qh->interval = urb->interval;
+00213                 
+00214 #if 0
+00215                 /* Increase interrupt polling rate for debugging. */
+00216                 if (qh->ep_type == UE_INTERRUPT) {
+00217                         qh->interval = 8;
+00218                 }
+00219 #endif
+00220                 hprt.d32 = dwc_read_reg32(hcd->core_if->host_if->hprt0);
+00221                 if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) &&
+00222                     ((dev_speed == USB_SPEED_LOW) ||
+00223                      (dev_speed == USB_SPEED_FULL))) {
+00224                         qh->interval *= 8;
+00225                         qh->sched_frame |= 0x7;
+00226                         qh->start_split_frame = qh->sched_frame;
+00227                 }
+00228 
+00229         }
+00230 
+00231         DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
+00232         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - qh = %p\n", qh);
+00233         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Device Address = %d\n",
+00234                     dwc_otg_hcd_get_dev_addr(&urb->pipe_info));
+00235         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Endpoint %d, %s\n",
+00236                     dwc_otg_hcd_get_ep_num(&urb->pipe_info),
+00237                     dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
+00238         switch (dev_speed) {
+00239         case USB_SPEED_LOW:
+00240                 qh->dev_speed = DWC_OTG_EP_SPEED_LOW;
+00241                 speed = "low";
+00242                 break;
+00243         case USB_SPEED_FULL:
+00244                 qh->dev_speed = DWC_OTG_EP_SPEED_FULL;
+00245                 speed = "full";
+00246                 break;
+00247         case USB_SPEED_HIGH:
+00248                 qh->dev_speed = DWC_OTG_EP_SPEED_HIGH;
+00249                 speed = "high";
+00250                 break;
+00251         default:
+00252                 speed = "?";
+00253                 break;
+00254         }
+00255         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Speed = %s\n", speed);
+00256 
+00257         switch (qh->ep_type) {
+00258         case UE_ISOCHRONOUS:
+00259                 type = "isochronous";
+00260                 break;
+00261         case UE_INTERRUPT:
+00262                 type = "interrupt";
+00263                 break;
+00264         case UE_CONTROL:
+00265                 type = "control";
+00266                 break;
+00267         case UE_BULK:
+00268                 type = "bulk";
+00269                 break;
+00270         default:
+00271                 type = "?";
+00272                 break;
+00273         }
+00274         
+00275         DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Type = %s\n", type);
+00276 
+00277 #ifdef DEBUG
+00278         if (qh->ep_type == UE_INTERRUPT) {
+00279                 DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n",
+00280                             qh->usecs);
+00281                 DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n",
+00282                             qh->interval);
+00283         }
+00284 #endif
+00285 
+00286 }
+00287 
+00296 dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
+00297                                     dwc_otg_hcd_urb_t * urb)
+00298 {
+00299         dwc_otg_qh_t *qh;
+00300 
+00301         /* Allocate memory */
+00303         qh = dwc_otg_hcd_qh_alloc();
+00304         if (qh == NULL) {
+00305                 return NULL;
+00306         }
+00307 
+00308         qh_init(hcd, qh, urb);
+00309         
+00310         if (hcd->core_if->dma_desc_enable && (dwc_otg_hcd_qh_init_ddma(hcd, qh) < 0)) {
+00311                 dwc_otg_hcd_qh_free(hcd, qh);   
+00312                 return NULL;
+00313         }
+00314         
+00315         return qh;
+00316 }
+00317 
+00323 static int periodic_channel_available(dwc_otg_hcd_t * hcd)
+00324 {
+00325         /*
+00326          * Currently assuming that there is a dedicated host channnel for each
+00327          * periodic transaction plus at least one host channel for
+00328          * non-periodic transactions.
+00329          */
+00330         int status;
+00331         int num_channels;
+00332 
+00333         num_channels = hcd->core_if->core_params->host_channels;
+00334         if ((hcd->periodic_channels + hcd->non_periodic_channels < num_channels) &&
+00335             (hcd->periodic_channels < num_channels - 1)) {
+00336                 status = 0;
+00337         } else {
+00338                 DWC_INFO("%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n",
+00339                         __func__, num_channels, hcd->periodic_channels, hcd->non_periodic_channels);    //NOTICE
+00340                 status = -DWC_E_NO_SPACE;
+00341         }
+00342 
+00343         return status;
+00344 }
+00345 
+00356 static int check_periodic_bandwidth(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+00357 {
+00358         int status;
+00359         int16_t max_claimed_usecs;
+00360 
+00361         status = 0;
+00362 
+00363         if ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) || qh->do_split) {
+00364                 /*
+00365                  * High speed mode.
+00366                  * Max periodic usecs is 80% x 125 usec = 100 usec.
+00367                  */
+00368 
+00369                 max_claimed_usecs = 100 - qh->usecs;
+00370         } else {
+00371                 /*
+00372                  * Full speed mode.
+00373                  * Max periodic usecs is 90% x 1000 usec = 900 usec.
+00374                  */
+00375                 max_claimed_usecs = 900 - qh->usecs;
+00376         }
+00377 
+00378         if (hcd->periodic_usecs > max_claimed_usecs) {
+00379                 DWC_INFO("%s: already claimed usecs %d, required usecs %d\n", __func__, hcd->periodic_usecs, qh->usecs);        //NOTICE
+00380                 status = -DWC_E_NO_SPACE;
+00381         }
+00382 
+00383         return status;
+00384 }
+00385 
+00396 static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+00397 {
+00398         int status;
+00399         uint32_t max_xfer_size;
+00400         uint32_t max_channel_xfer_size;
+00401 
+00402         status = 0;
+00403 
+00404         max_xfer_size = dwc_max_packet(qh->maxp) * dwc_hb_mult(qh->maxp);
+00405         max_channel_xfer_size = hcd->core_if->core_params->max_transfer_size;
+00406 
+00407         if (max_xfer_size > max_channel_xfer_size) {
+00408                 DWC_INFO("%s: Periodic xfer length %d > " "max xfer length for channel %d\n",
+00409                                 __func__, max_xfer_size, max_channel_xfer_size);        //NOTICE
+00410                 status = -DWC_E_NO_SPACE;
+00411         }
+00412 
+00413         return status;
+00414 }
+00415 
+00425 static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+00426 {
+00427         int status = 0;
+00428 
+00429         status = periodic_channel_available(hcd);
+00430         if (status) {
+00431                 DWC_INFO("%s: No host channel available for periodic " "transfer.\n", __func__);        //NOTICE
+00432                 return status;
+00433         }
+00434 
+00435         status = check_periodic_bandwidth(hcd, qh);
+00436         if (status) {
+00437                 DWC_INFO("%s: Insufficient periodic bandwidth for " "periodic transfer.\n", __func__);  //NOTICE
+00438                 return status;
+00439         }
+00440 
+00441         status = check_max_xfer_size(hcd, qh);
+00442         if (status) {
+00443                 DWC_INFO("%s: Channel max transfer size too small " "for periodic transfer.\n", __func__);      //NOTICE
+00444                 return status;
+00445         }
+00446 
+00447         if (hcd->core_if->dma_desc_enable) {
+00448                 /* Don't rely on SOF and start in ready schedule */
+00449                 DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry);
+00450         }
+00451         else {
+00452         /* Always start in the inactive schedule. */
+00453         DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry);
+00454         }
+00455 
+00456         /* Reserve the periodic channel. */
+00457         hcd->periodic_channels++;
+00458 
+00459         /* Update claimed usecs per (micro)frame. */
+00460         hcd->periodic_usecs += qh->usecs;
+00461 
+00462         return status;
+00463 }
+00464 
+00472 int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+00473 {
+00474         int status = 0;
+00475         uint64_t flags;
+00476 
+00477         DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
+00478 
+00479         if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) {
+00480                 /* QH already in a schedule. */
+00481                 goto done;
+00482         }
+00483 
+00484         /* Add the new QH to the appropriate schedule */
+00485         if (dwc_qh_is_non_per(qh)) {
+00486                 /* Always start in the inactive schedule. */
+00487                 DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive,
+00488                                      &qh->qh_list_entry);
+00489         } else {
+00490                 status = schedule_periodic(hcd, qh);
+00491         }
+00492 
+00493       done:
+00494         DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
+00495 
+00496         return status;
+00497 }
+00498 
+00505 static void deschedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+00506 {
+00507         DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
+00508 
+00509         /* Release the periodic channel reservation. */
+00510         hcd->periodic_channels--;
+00511 
+00512         /* Update claimed usecs per (micro)frame. */
+00513         hcd->periodic_usecs -= qh->usecs;
+00514 }
+00515 
+00522 void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
+00523 {
+00524         uint64_t flags;
+00525         DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
+00526 
+00527         if (DWC_LIST_EMPTY(&qh->qh_list_entry)) {
+00528                 /* QH is not in a schedule. */
+00529                 goto done;
+00530         }
+00531 
+00532         if (dwc_qh_is_non_per(qh)) {
+00533                 if (hcd->non_periodic_qh_ptr == &qh->qh_list_entry) {
+00534                         hcd->non_periodic_qh_ptr =
+00535                             hcd->non_periodic_qh_ptr->next;
+00536                 }
+00537                 DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
+00538         } else {
+00539                 deschedule_periodic(hcd, qh);
+00540         }
+00541 
+00542       done:
+00543         DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
+00544 }
+00545 
+00559 void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
+00560                                int sched_next_periodic_split)
+00561 {
+00562         uint64_t flags;
+00563         DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
+00564 
+00565         if (dwc_qh_is_non_per(qh)) {
+00566                 dwc_otg_hcd_qh_remove(hcd, qh);
+00567                 if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
+00568                         /* Add back to inactive non-periodic schedule. */
+00569                         dwc_otg_hcd_qh_add(hcd, qh);
+00570                 }
+00571         } else {
+00572                 uint16_t frame_number = dwc_otg_hcd_get_frame_number(hcd);
+00573 
+00574                 if (qh->do_split) {
+00575                         /* Schedule the next continuing periodic split transfer */
+00576                         if (sched_next_periodic_split) {
+00577 
+00578                                 qh->sched_frame = frame_number;
+00579                                 if (dwc_frame_num_le(frame_number,
+00580                                                      dwc_frame_num_inc(qh->
+00581                                                                        start_split_frame,
+00582                                                                        1))) {
+00583                                         /*
+00584                                          * Allow one frame to elapse after start
+00585                                          * split microframe before scheduling
+00586                                          * complete split, but DONT if we are
+00587                                          * doing the next start split in the
+00588                                          * same frame for an ISOC out.
+00589                                          */
+00590                                         if ((qh->ep_type != UE_ISOCHRONOUS) ||
+00591                                             (qh->ep_is_in != 0)) {
+00592                                                 qh->sched_frame =
+00593                                                     dwc_frame_num_inc(qh->sched_frame, 1);
+00594                                         }
+00595                                 }
+00596                         } else {
+00597                                 qh->sched_frame =
+00598                                     dwc_frame_num_inc(qh->start_split_frame,
+00599                                                       qh->interval);
+00600                                 if (dwc_frame_num_le
+00601                                     (qh->sched_frame, frame_number)) {
+00602                                         qh->sched_frame = frame_number;
+00603                                 }
+00604                                 qh->sched_frame |= 0x7;
+00605                                 qh->start_split_frame = qh->sched_frame;
+00606                         }
+00607                 } else {
+00608                         qh->sched_frame =
+00609                             dwc_frame_num_inc(qh->sched_frame, qh->interval);
+00610                         if (dwc_frame_num_le(qh->sched_frame, frame_number)) {
+00611                                 qh->sched_frame = frame_number;
+00612                         }
+00613                 }
+00614 
+00615                 if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
+00616                         dwc_otg_hcd_qh_remove(hcd, qh);
+00617                 } else {
+00618                         /*
+00619                          * Remove from periodic_sched_queued and move to
+00620                          * appropriate queue.
+00621                          */
+00622                         if (qh->sched_frame == frame_number) {
+00623                                 DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
+00624                                                    &qh->qh_list_entry);
+00625                         } else {
+00626                                 DWC_LIST_MOVE_HEAD(&hcd->
+00627                                                    periodic_sched_inactive,
+00628                                                    &qh->qh_list_entry);
+00629                         }
+00630                 }
+00631         }
+00632 
+00633         DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
+00634 }
+00635 
+00643 dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb)
+00644 {
+00645         dwc_otg_qtd_t *qtd;
+00646 
+00647         qtd = dwc_otg_hcd_qtd_alloc();
+00648         if (qtd == NULL) {
+00649                 return NULL;
+00650         }
+00651 
+00652         dwc_otg_hcd_qtd_init(qtd, urb);
+00653         return qtd;
+00654 }
+00655 
+00661 void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb)
+00662 {
+00663         dwc_memset(qtd, 0, sizeof(dwc_otg_qtd_t));
+00664         qtd->urb = urb;
+00665         if (dwc_otg_hcd_get_pipe_type(&urb->pipe_info) == UE_CONTROL) {
+00666                 /*
+00667                  * The only time the QTD data toggle is used is on the data
+00668                  * phase of control transfers. This phase always starts with
+00669                  * DATA1.
+00670                  */
+00671                 qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
+00672                 qtd->control_phase = DWC_OTG_CONTROL_SETUP;
+00673         }
+00674 
+00675         /* start split */
+00676         qtd->complete_split = 0;
+00677         qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
+00678         qtd->isoc_split_offset = 0;
+00679         qtd->in_process = 0;
+00680 
+00681         /* Store the qtd ptr in the urb to reference what QTD. */
+00682         urb->qtd = qtd;
+00683         return;
+00684 }
+00685 
+00698 int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
+00699                         dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh)
+00700 {
+00701         int retval = 0;
+00702         uint64_t flags;
+00703 
+00704         dwc_otg_hcd_urb_t *urb = qtd->urb;
+00705 
+00706         DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
+00707 
+00708         /*
+00709          * Get the QH which holds the QTD-list to insert to. Create QH if it
+00710          * doesn't exist.
+00711          */
+00712         if (*qh == NULL) {
+00713                 *qh = dwc_otg_hcd_qh_create(hcd, urb);
+00714                 if (*qh == NULL) {
+00715                         retval = -1;
+00716                         goto done;
+00717                 }
+00718         }
+00719 
+00720         retval = dwc_otg_hcd_qh_add(hcd, *qh);
+00721         if (retval == 0) {
+00722                 DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd,
+00723                                         qtd_list_entry);
+00724         }
+00725 
+00726       done:
+00727         DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
+00728 
+00729         return retval;
+00730 }
+00731 
+00732 #endif                          /* DWC_DEVICE_ONLY */
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__queue_8c.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__queue_8c.html new file mode 100644 index 000000000000..13f68b1b7bd0 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__hcd__queue_8c.html @@ -0,0 +1,667 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hcd_queue.c File Reference + + + + + + +

dwc_otg_hcd_queue.c File Reference

This file contains the functions to manage Queue Heads and Queue Transfer Descriptors. More... +

+#include "dwc_otg_hcd.h"
+#include "dwc_otg_regs.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Defines

+#define BitStuffTime(bytecount)   ((8 * 7* bytecount) / 6)
+#define HS_HOST_DELAY   5
+#define FS_LS_HOST_DELAY   1000
+#define HUB_LS_SETUP   333
+#define NS_TO_US(ns)   ((ns + 500) / 1000)
#define SCHEDULE_SLOP   10
 Initializes a QH structure.

Functions

void dwc_otg_hcd_qh_free (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
 Free each QTD in the QH's QTD-list then free the QH.
+static uint32_t calc_bus_time (int speed, int is_in, int is_isoc, int bytecount)
void qh_init (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, dwc_otg_hcd_urb_t *urb)
dwc_otg_qh_tdwc_otg_hcd_qh_create (dwc_otg_hcd_t *hcd, dwc_otg_hcd_urb_t *urb)
 This function allocates and initializes a QH.
static int periodic_channel_available (dwc_otg_hcd_t *hcd)
 Checks that a channel is available for a periodic transfer.
static int check_periodic_bandwidth (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
 Checks that there is sufficient bandwidth for the specified QH in the periodic schedule.
static int check_max_xfer_size (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
 Checks that the max transfer size allowed in a host channel is large enough to handle the maximum data transfer in a single (micro)frame for a periodic transfer.
static int schedule_periodic (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
 Schedules an interrupt or isochronous transfer in the periodic schedule.
int dwc_otg_hcd_qh_add (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
 This function adds a QH to either the non periodic or periodic schedule if it is not already in the schedule.
static void deschedule_periodic (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
 Removes an interrupt or isochronous transfer from the periodic schedule.
void dwc_otg_hcd_qh_remove (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
 Removes a QH from either the non-periodic or periodic schedule.
void dwc_otg_hcd_qh_deactivate (dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, int sched_next_periodic_split)
 Deactivates a QH.
dwc_otg_qtd_tdwc_otg_hcd_qtd_create (dwc_otg_hcd_urb_t *urb)
 This function allocates and initializes a QTD.
void dwc_otg_hcd_qtd_init (dwc_otg_qtd_t *qtd, dwc_otg_hcd_urb_t *urb)
 Initializes a QTD structure.
int dwc_otg_hcd_qtd_add (dwc_otg_qtd_t *qtd, dwc_otg_hcd_t *hcd, dwc_otg_qh_t **qh)
 This function adds a QTD to the QTD-list of a QH.
+


Detailed Description

+This file contains the functions to manage Queue Heads and Queue Transfer Descriptors. +

+ +

+Definition in file dwc_otg_hcd_queue.c.


Define Documentation

+ +
+
+ + + + +
#define SCHEDULE_SLOP   10
+
+
+ +

+Initializes a QH structure. +

+

Parameters:
+ + + + +
hcd The HCD state structure for the DWC OTG controller.
qh The QH to init.
urb Holds the information about the device/endpoint that we need to initialize the QH.
+
+ +

+Definition at line 159 of file dwc_otg_hcd_queue.c. +

+

+


Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_qh_free (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh 
)
+
+
+ +

+Free each QTD in the QH's QTD-list then free the QH. +

+QH should already be removed from a list. QTD list should already be empty if called from URB Dequeue.

+

Parameters:
+ + + +
hcd HCD instance.
qh The QH to free.
+
+ +

+Definition at line 53 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void qh_init (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh,
dwc_otg_hcd_urb_t urb 
)
+
+
+ +

+ +

+Definition at line 160 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
dwc_otg_qh_t* dwc_otg_hcd_qh_create (dwc_otg_hcd_t hcd,
dwc_otg_hcd_urb_t urb 
)
+
+
+ +

+This function allocates and initializes a QH. +

+

Parameters:
+ + + +
hcd The HCD state structure for the DWC OTG controller.
urb Holds the information about the device/endpoint that we need to initialize the QH.
+
+
Returns:
Returns pointer to the newly allocated QH, or NULL on error.
+ +

+

Todo:
add memflags argument
+ +

+Definition at line 296 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + +
static int periodic_channel_available (dwc_otg_hcd_t hcd  )  [static]
+
+
+ +

+Checks that a channel is available for a periodic transfer. +

+

Returns:
0 if successful, negative error code otherise.
+ +

+Definition at line 323 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static int check_periodic_bandwidth (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh 
) [static]
+
+
+ +

+Checks that there is sufficient bandwidth for the specified QH in the periodic schedule. +

+For simplicity, this calculation assumes that all the transfers in the periodic schedule may occur in the same (micro)frame.

+

Parameters:
+ + + +
hcd The HCD state structure for the DWC OTG controller.
qh QH containing periodic bandwidth required.
+
+
Returns:
0 if successful, negative error code otherwise.
+ +

+Definition at line 356 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static int check_max_xfer_size (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh 
) [static]
+
+
+ +

+Checks that the max transfer size allowed in a host channel is large enough to handle the maximum data transfer in a single (micro)frame for a periodic transfer. +

+

Parameters:
+ + + +
hcd The HCD state structure for the DWC OTG controller.
qh QH for a periodic endpoint.
+
+
Returns:
0 if successful, negative error code otherwise.
+ +

+Definition at line 396 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static int schedule_periodic (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh 
) [static]
+
+
+ +

+Schedules an interrupt or isochronous transfer in the periodic schedule. +

+

Parameters:
+ + + +
hcd The HCD state structure for the DWC OTG controller.
qh QH for the periodic transfer. The QH should already contain the scheduling information.
+
+
Returns:
0 if successful, negative error code otherwise.
+ +

+Definition at line 425 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_qh_add (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh 
)
+
+
+ +

+This function adds a QH to either the non periodic or periodic schedule if it is not already in the schedule. +

+If the QH is already in the schedule, no action is taken.

+

Returns:
0 if successful, negative error code otherwise.
+ +

+Definition at line 472 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static void deschedule_periodic (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh 
) [static]
+
+
+ +

+Removes an interrupt or isochronous transfer from the periodic schedule. +

+

Parameters:
+ + + +
hcd The HCD state structure for the DWC OTG controller.
qh QH for the periodic transfer.
+
+ +

+Definition at line 505 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_qh_remove (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh 
)
+
+
+ +

+Removes a QH from either the non-periodic or periodic schedule. +

+Memory is not freed.

+

Parameters:
+ + + +
hcd The HCD state structure.
qh QH to remove from schedule.
+
+ +

+Definition at line 522 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_qh_deactivate (dwc_otg_hcd_t hcd,
dwc_otg_qh_t qh,
int  sched_next_periodic_split 
)
+
+
+ +

+Deactivates a QH. +

+For non-periodic QHs, removes the QH from the active non-periodic schedule. The QH is added to the inactive non-periodic schedule if any QTDs are still attached to the QH.

+For periodic QHs, the QH is removed from the periodic queued schedule. If there are any QTDs still attached to the QH, the QH is added to either the periodic inactive schedule or the periodic ready schedule and its next scheduled frame is calculated. The QH is placed in the ready schedule if the scheduled frame has been reached already. Otherwise it's placed in the inactive schedule. If there are no QTDs attached to the QH, the QH is completely removed from the periodic schedule. +

+Definition at line 559 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + +
dwc_otg_qtd_t* dwc_otg_hcd_qtd_create (dwc_otg_hcd_urb_t urb  ) 
+
+
+ +

+This function allocates and initializes a QTD. +

+

Parameters:
+ + +
urb The URB to create a QTD from. Each URB-QTD pair will end up pointing to each other so each pair should have a unique correlation.
+
+
Returns:
Returns pointer to the newly allocated QTD, or NULL on error.
+ +

+Definition at line 643 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_hcd_qtd_init (dwc_otg_qtd_t qtd,
dwc_otg_hcd_urb_t urb 
)
+
+
+ +

+Initializes a QTD structure. +

+

Parameters:
+ + + +
qtd The QTD to initialize.
urb The URB to use for initialization.
+
+ +

+Definition at line 661 of file dwc_otg_hcd_queue.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_hcd_qtd_add (dwc_otg_qtd_t qtd,
dwc_otg_hcd_t hcd,
dwc_otg_qh_t **  qh 
)
+
+
+ +

+This function adds a QTD to the QTD-list of a QH. +

+It will find the correct QH to place the QTD into. If it does not find a QH, then it will create a new QH. If the QH to which the QTD is added is not currently scheduled, it is placed into the proper schedule based on its EP type.

+

Parameters:
+ + + + +
[in] qtd The QTD to add
[in] hcd The DWC HCD structure
[out] qh out parameter to return queue head
+
+
Returns:
0 if successful, negative error code otherwise.
+ +

+Definition at line 698 of file dwc_otg_hcd_queue.c. +

+

+


Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd_8c-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd_8c-source.html new file mode 100644 index 000000000000..da7e6176107e --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd_8c-source.html @@ -0,0 +1,1851 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_pcd.c Source File + + + + + + +

dwc_otg_pcd.c

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.c $
+00003  * $Revision: #79 $
+00004  * $Date: 2009/04/10 $
+00005  * $Change: 1230501 $
+00006  *
+00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009  * otherwise expressly agreed to in writing between Synopsys and you.
+00010  *
+00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012  * any End User Software License Agreement or Agreement for Licensed Product
+00013  * with Synopsys or any supplement thereto. You are permitted to use and
+00014  * redistribute this Software in source and binary forms, with or without
+00015  * modification, provided that redistributions of source code must retain this
+00016  * notice. You may not view, use, disclose, copy or distribute this file or
+00017  * any information contained herein except pursuant to this license grant from
+00018  * Synopsys. If you do not agree with this notice, including the disclaimer
+00019  * below, then you are not authorized to use the Software.
+00020  *
+00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031  * DAMAGE.
+00032  * ========================================================================== */
+00033 #ifndef DWC_HOST_ONLY
+00034 
+00051 #include "dwc_otg_pcd.h"
+00052 
+00053 #ifdef DWC_UTE_CFI
+00054 #include "dwc_otg_cfi.h"
+00055 
+00056 extern int init_cfi(cfiobject_t * cfiobj);
+00057 #endif
+00058 
+00059 static dwc_otg_pcd_ep_t *get_ep_from_handle(dwc_otg_pcd_t * pcd, void *handle)
+00060 {
+00061         int i;
+00062         if (pcd->ep0.priv == handle) {
+00063                 return &pcd->ep0;
+00064         }
+00065         for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) {
+00066                 if (pcd->in_ep[i].priv == handle)
+00067                         return &pcd->in_ep[i];
+00068                 if (pcd->out_ep[i].priv == handle)
+00069                         return &pcd->out_ep[i];
+00070         }
+00071 
+00072         return NULL;
+00073 }
+00074 
+00078 void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req,
+00079                           int32_t status)
+00080 {
+00081         unsigned stopped = ep->stopped;
+00082 
+00083         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, ep);
+00084         DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry);
+00085 
+00086         /* don't modify queue heads during completion callback */
+00087         ep->stopped = 1;
+00088         DWC_SPINUNLOCK(ep->pcd->lock);
+00089         ep->pcd->fops->complete(ep->pcd, ep->priv, req->priv, status,
+00090                                 req->actual);
+00091         DWC_SPINLOCK(ep->pcd->lock);
+00092 
+00093         if (ep->pcd->request_pending > 0) {
+00094                 --ep->pcd->request_pending;
+00095         }
+00096 
+00097         ep->stopped = stopped;
+00098         dwc_free(req);
+00099 }
+00100 
+00104 void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep)
+00105 {
+00106         dwc_otg_pcd_request_t *req;
+00107 
+00108         ep->stopped = 1;
+00109 
+00110         /* called with irqs blocked?? */
+00111         while (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
+00112                 req = DWC_CIRCLEQ_FIRST(&ep->queue);
+00113                 dwc_otg_request_done(ep, req, -DWC_E_SHUTDOWN);
+00114         }
+00115 }
+00116 
+00117 void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
+00118                        const struct dwc_otg_pcd_function_ops *fops)
+00119 {
+00120         pcd->fops = fops;
+00121 }
+00122 
+00129 static int32_t dwc_otg_pcd_start_cb(void *p)
+00130 {
+00131         dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
+00132 
+00133         /*
+00134          * Initialized the Core for Device mode.
+00135          */
+00136         if (dwc_otg_is_device_mode(GET_CORE_IF(pcd))) {
+00137                 dwc_otg_core_dev_init(GET_CORE_IF(pcd));
+00138         }
+00139         return 1;
+00140 }
+00141 
+00143 #ifdef DWC_UTE_CFI
+00144 uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
+00145                               size_t buflen, int flags)
+00146 {
+00147         dwc_otg_pcd_ep_t *ep;
+00148         ep = get_ep_from_handle(pcd, pep);
+00149         return pcd->cfi->ops.ep_alloc_buf(pcd->cfi, pcd, ep, addr, buflen,
+00150                                           flags);
+00151 }
+00152 #else
+00153 uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr,
+00154                               size_t buflen, int flags);
+00155 #endif
+00156 
+00163 static int32_t dwc_otg_pcd_resume_cb(void *p)
+00164 {
+00165         dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
+00166 
+00167         if (pcd->fops->resume) {
+00168                 pcd->fops->resume(pcd);
+00169         }
+00170 
+00171         /* Stop the SRP timeout timer. */
+00172         if ((GET_CORE_IF(pcd)->core_params->phy_type != DWC_PHY_TYPE_PARAM_FS)
+00173             || (!GET_CORE_IF(pcd)->core_params->i2c_enable)) {
+00174                 if (GET_CORE_IF(pcd)->srp_timer_started) {
+00175                         GET_CORE_IF(pcd)->srp_timer_started = 0;
+00176                         DWC_TIMER_CANCEL(pcd->srp_timer);
+00177                 }
+00178         }
+00179         return 1;
+00180 }
+00181 
+00187 static int32_t dwc_otg_pcd_suspend_cb(void *p)
+00188 {
+00189         dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
+00190 
+00191         if (pcd->fops->suspend) {
+00192                 pcd->fops->suspend(pcd);
+00193         }
+00194 
+00195         return 1;
+00196 }
+00197 
+00204 static int32_t dwc_otg_pcd_stop_cb(void *p)
+00205 {
+00206         dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p;
+00207         extern void dwc_otg_pcd_stop(dwc_otg_pcd_t * _pcd);
+00208 
+00209         dwc_otg_pcd_stop(pcd);
+00210         return 1;
+00211 }
+00212 
+00216 static dwc_otg_cil_callbacks_t pcd_callbacks = {
+00217         .start = dwc_otg_pcd_start_cb,
+00218         .stop = dwc_otg_pcd_stop_cb,
+00219         .suspend = dwc_otg_pcd_suspend_cb,
+00220         .resume_wakeup = dwc_otg_pcd_resume_cb,
+00221         .p = 0,                 /* Set at registration */
+00222 };
+00223 
+00228 dwc_otg_dev_dma_desc_t *dwc_otg_ep_alloc_desc_chain(uint32_t * dma_desc_addr,
+00229                                                 uint32_t count)
+00230 {
+00231 
+00232         return dwc_dma_alloc(count * sizeof(dwc_otg_dev_dma_desc_t), dma_desc_addr);
+00233 }
+00234 
+00238 void dwc_otg_ep_free_desc_chain(dwc_otg_dev_dma_desc_t * desc_addr,
+00239                                 uint32_t dma_desc_addr, uint32_t count)
+00240 {
+00241         dwc_dma_free(count * sizeof(dwc_otg_dev_dma_desc_t), desc_addr,
+00242                      dma_desc_addr);
+00243 }
+00244 
+00245 #ifdef DWC_EN_ISOC
+00246 
+00254 void dwc_otg_iso_ep_start_ddma_transfer(dwc_otg_core_if_t * core_if,
+00255                                         dwc_ep_t * dwc_ep)
+00256 {
+00257 
+00258         dsts_data_t dsts = {.d32 = 0 };
+00259         depctl_data_t depctl = {.d32 = 0 };
+00260         volatile uint32_t *addr;
+00261         int i, j;
+00262 
+00263         if (dwc_ep->is_in)
+00264                 dwc_ep->desc_cnt = dwc_ep->buf_proc_intrvl / dwc_ep->bInterval;
+00265         else
+00266                 dwc_ep->desc_cnt =
+00267                     dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
+00268                     dwc_ep->bInterval;
+00269 
+00271         dwc_ep->iso_desc_addr =
+00272             dwc_otg_ep_alloc_desc_chain(&dwc_ep->iso_dma_desc_addr,
+00273                                         dwc_ep->desc_cnt * 2);
+00274         if (dwc_ep->desc_addr) {
+00275                 DWC_WARN("%s, can't allocate DMA descriptor chain\n", __func__);
+00276                 return;
+00277         }
+00278 
+00279         dsts.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
+00280 
+00282         if (dwc_ep->is_in == 0) {
+00283                 dev_dma_desc_sts_t sts = {.d32 = 0 };
+00284                 dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
+00285                 dma_addr_t dma_ad;
+00286                 uint32_t data_per_desc;
+00287                 dwc_otg_dev_out_ep_regs_t *out_regs =
+00288                     core_if->dev_if->out_ep_regs[dwc_ep->num];
+00289                 int offset;
+00290 
+00291                 addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
+00292                 dma_ad = (dma_addr_t) dwc_read_reg32(&(out_regs->doepdma));
+00293 
+00295                 dma_ad = dwc_ep->dma_addr0;
+00296 
+00297                 sts.b_iso_out.bs = BS_HOST_READY;
+00298                 sts.b_iso_out.rxsts = 0;
+00299                 sts.b_iso_out.l = 0;
+00300                 sts.b_iso_out.sp = 0;
+00301                 sts.b_iso_out.ioc = 0;
+00302                 sts.b_iso_out.pid = 0;
+00303                 sts.b_iso_out.framenum = 0;
+00304 
+00305                 offset = 0;
+00306                 for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
+00307                      i += dwc_ep->pkt_per_frm) {
+00308 
+00309                         for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
+00310                                 data_per_desc =
+00311                                     ((j + 1) * dwc_ep->maxpacket >
+00312                                      dwc_ep->data_per_frame) ? dwc_ep->
+00313                                     data_per_frame -
+00314                                     j * dwc_ep->maxpacket : dwc_ep->maxpacket;
+00315 
+00316                                 data_per_desc +=
+00317                                     (data_per_desc % 4) ? (4 -
+00318                                                            data_per_desc %
+00319                                                            4) : 0;
+00320                                 sts.b_iso_out.rxbytes = data_per_desc;
+00321                                 dma_desc->buf = dma_ad;
+00322                                 dma_desc->status.d32 = sts.d32;
+00323 
+00324                                 offset += data_per_desc;
+00325                                 dma_desc++;
+00326                                 dma_ad += data_per_desc;
+00327                         }
+00328                 }
+00329 
+00330                 for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
+00331                         data_per_desc =
+00332                             ((j + 1) * dwc_ep->maxpacket >
+00333                              dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
+00334                             j * dwc_ep->maxpacket : dwc_ep->maxpacket;
+00335                         data_per_desc +=
+00336                             (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
+00337                         sts.b_iso_out.rxbytes = data_per_desc;
+00338                         dma_desc->buf = dma_ad;
+00339                         dma_desc->status.d32 = sts.d32;
+00340 
+00341                         offset += data_per_desc;
+00342                         dma_desc++;
+00343                         dma_ad += data_per_desc;
+00344                 }
+00345 
+00346                 sts.b_iso_out.ioc = 1;
+00347                 data_per_desc =
+00348                     ((j + 1) * dwc_ep->maxpacket >
+00349                      dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
+00350                     j * dwc_ep->maxpacket : dwc_ep->maxpacket;
+00351                 data_per_desc +=
+00352                     (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
+00353                 sts.b_iso_out.rxbytes = data_per_desc;
+00354 
+00355                 dma_desc->buf = dma_ad;
+00356                 dma_desc->status.d32 = sts.d32;
+00357                 dma_desc++;
+00358 
+00360                 sts.b_iso_out.ioc = 0;
+00361                 dma_ad = dwc_ep->dma_addr1;
+00362 
+00363                 offset = 0;
+00364                 for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
+00365                      i += dwc_ep->pkt_per_frm) {
+00366                         for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
+00367                                 data_per_desc =
+00368                                     ((j + 1) * dwc_ep->maxpacket >
+00369                                      dwc_ep->data_per_frame) ? dwc_ep->
+00370                                     data_per_frame -
+00371                                     j * dwc_ep->maxpacket : dwc_ep->maxpacket;
+00372                                 data_per_desc +=
+00373                                     (data_per_desc % 4) ? (4 -
+00374                                                            data_per_desc %
+00375                                                            4) : 0;
+00376                                 sts.b_iso_out.rxbytes = data_per_desc;
+00377                                 dma_desc->buf = dma_ad;
+00378                                 dma_desc->status.d32 = sts.d32;
+00379 
+00380                                 offset += data_per_desc;
+00381                                 dma_desc++;
+00382                                 dma_ad += data_per_desc;
+00383                         }
+00384                 }
+00385                 for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
+00386                         data_per_desc =
+00387                             ((j + 1) * dwc_ep->maxpacket >
+00388                              dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
+00389                             j * dwc_ep->maxpacket : dwc_ep->maxpacket;
+00390                         data_per_desc +=
+00391                             (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
+00392                         sts.b_iso_out.rxbytes = data_per_desc;
+00393                         dma_desc->buf = dma_ad;
+00394                         dma_desc->status.d32 = sts.d32;
+00395 
+00396                         offset += data_per_desc;
+00397                         dma_desc++;
+00398                         dma_ad += data_per_desc;
+00399                 }
+00400 
+00401                 sts.b_iso_out.ioc = 1;
+00402                 sts.b_iso_out.l = 1;
+00403                 data_per_desc =
+00404                     ((j + 1) * dwc_ep->maxpacket >
+00405                      dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
+00406                     j * dwc_ep->maxpacket : dwc_ep->maxpacket;
+00407                 data_per_desc +=
+00408                     (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
+00409                 sts.b_iso_out.rxbytes = data_per_desc;
+00410 
+00411                 dma_desc->buf = dma_ad;
+00412                 dma_desc->status.d32 = sts.d32;
+00413 
+00414                 dwc_ep->next_frame = 0;
+00415 
+00417                 dwc_write_reg32(&(out_regs->doepdma),
+00418                                 (uint32_t) dwc_ep->iso_dma_desc_addr);
+00419 
+00420         }
+00422         else {
+00423                 dev_dma_desc_sts_t sts = {.d32 = 0 };
+00424                 dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr;
+00425                 dma_addr_t dma_ad;
+00426                 dwc_otg_dev_in_ep_regs_t *in_regs =
+00427                     core_if->dev_if->in_ep_regs[dwc_ep->num];
+00428                 unsigned int frmnumber;
+00429                 fifosize_data_t txfifosize, rxfifosize;
+00430 
+00431                 txfifosize.d32 =
+00432                     dwc_read_reg32(&core_if->dev_if->in_ep_regs[dwc_ep->num]->
+00433                                    dtxfsts);
+00434                 rxfifosize.d32 =
+00435                     dwc_read_reg32(&core_if->core_global_regs->grxfsiz);
+00436 
+00437                 addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
+00438 
+00439                 dma_ad = dwc_ep->dma_addr0;
+00440 
+00441                 dsts.d32 =
+00442                     dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
+00443 
+00444                 sts.b_iso_in.bs = BS_HOST_READY;
+00445                 sts.b_iso_in.txsts = 0;
+00446                 sts.b_iso_in.sp =
+00447                     (dwc_ep->data_per_frame % dwc_ep->maxpacket) ? 1 : 0;
+00448                 sts.b_iso_in.ioc = 0;
+00449                 sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
+00450 
+00451                 frmnumber = dwc_ep->next_frame;
+00452 
+00453                 sts.b_iso_in.framenum = frmnumber;
+00454                 sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
+00455                 sts.b_iso_in.l = 0;
+00456 
+00458                 for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
+00459                         dma_desc->buf = dma_ad;
+00460                         dma_desc->status.d32 = sts.d32;
+00461                         dma_desc++;
+00462 
+00463                         dma_ad += dwc_ep->data_per_frame;
+00464                         sts.b_iso_in.framenum += dwc_ep->bInterval;
+00465                 }
+00466 
+00467                 sts.b_iso_in.ioc = 1;
+00468                 dma_desc->buf = dma_ad;
+00469                 dma_desc->status.d32 = sts.d32;
+00470                 ++dma_desc;
+00471 
+00473                 sts.b_iso_in.ioc = 0;
+00474                 dma_ad = dwc_ep->dma_addr1;
+00475 
+00476                 for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
+00477                      i += dwc_ep->pkt_per_frm) {
+00478                         dma_desc->buf = dma_ad;
+00479                         dma_desc->status.d32 = sts.d32;
+00480                         dma_desc++;
+00481 
+00482                         dma_ad += dwc_ep->data_per_frame;
+00483                         sts.b_iso_in.framenum += dwc_ep->bInterval;
+00484 
+00485                         sts.b_iso_in.ioc = 0;
+00486                 }
+00487                 sts.b_iso_in.ioc = 1;
+00488                 sts.b_iso_in.l = 1;
+00489 
+00490                 dma_desc->buf = dma_ad;
+00491                 dma_desc->status.d32 = sts.d32;
+00492 
+00493                 dwc_ep->next_frame = sts.b_iso_in.framenum + dwc_ep->bInterval;
+00494 
+00496                 dwc_write_reg32(&(in_regs->diepdma),
+00497                                 (uint32_t) dwc_ep->iso_dma_desc_addr);
+00498         }
+00500         depctl.d32 = 0;
+00501         depctl.b.epena = 1;
+00502         depctl.b.usbactep = 1;
+00503         depctl.b.cnak = 1;
+00504 
+00505         dwc_modify_reg32(addr, depctl.d32, depctl.d32);
+00506         depctl.d32 = dwc_read_reg32(addr);
+00507 }
+00508 
+00517 void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if,
+00518                                        dwc_ep_t * ep)
+00519 {
+00520         depctl_data_t depctl = {.d32 = 0 };
+00521         volatile uint32_t *addr;
+00522 
+00523         if (ep->is_in) {
+00524                 addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
+00525         } else {
+00526                 addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
+00527         }
+00528 
+00529         if (core_if->dma_enable == 0 || core_if->dma_desc_enable != 0) {
+00530                 return;
+00531         } else {
+00532                 deptsiz_data_t deptsiz = {.d32 = 0 };
+00533 
+00534                 ep->xfer_len =
+00535                     ep->data_per_frame * ep->buf_proc_intrvl / ep->bInterval;
+00536                 ep->pkt_cnt =
+00537                     (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
+00538                 ep->xfer_count = 0;
+00539                 ep->xfer_buff =
+00540                     (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
+00541                 ep->dma_addr =
+00542                     (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
+00543 
+00544                 if (ep->is_in) {
+00545                         /* Program the transfer size and packet count
+00546                          *      as follows: xfersize = N * maxpacket +
+00547                          *      short_packet pktcnt = N + (short_packet
+00548                          *      exist ? 1 : 0)  
+00549                          */
+00550                         deptsiz.b.mc = ep->pkt_per_frm;
+00551                         deptsiz.b.xfersize = ep->xfer_len;
+00552                         deptsiz.b.pktcnt =
+00553                             (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
+00554                         dwc_write_reg32(&core_if->dev_if->in_ep_regs[ep->num]->
+00555                                         dieptsiz, deptsiz.d32);
+00556 
+00557                         /* Write the DMA register */
+00558                         dwc_write_reg32(&
+00559                                         (core_if->dev_if->in_ep_regs[ep->num]->
+00560                                          diepdma), (uint32_t) ep->dma_addr);
+00561 
+00562                 } else {
+00563                         deptsiz.b.pktcnt =
+00564                             (ep->xfer_len + (ep->maxpacket - 1)) /
+00565                             ep->maxpacket;
+00566                         deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
+00567 
+00568                         dwc_write_reg32(&core_if->dev_if->out_ep_regs[ep->num]->
+00569                                         doeptsiz, deptsiz.d32);
+00570 
+00571                         /* Write the DMA register */
+00572                         dwc_write_reg32(&
+00573                                         (core_if->dev_if->out_ep_regs[ep->num]->
+00574                                          doepdma), (uint32_t) ep->dma_addr);
+00575 
+00576                 }
+00578                 depctl.d32 = 0;
+00579                 dwc_modify_reg32(addr, depctl.d32, depctl.d32);
+00580 
+00581                 depctl.b.epena = 1;
+00582                 depctl.b.cnak = 1;
+00583 
+00584                 dwc_modify_reg32(addr, depctl.d32, depctl.d32);
+00585         }
+00586 }
+00587 
+00598 static void dwc_otg_iso_ep_start_transfer(dwc_otg_core_if_t * core_if,
+00599                                           dwc_ep_t * ep)
+00600 {
+00601         if (core_if->dma_enable) {
+00602                 if (core_if->dma_desc_enable) {
+00603                         if (ep->is_in) {
+00604                                 ep->desc_cnt = ep->pkt_cnt / ep->pkt_per_frm;
+00605                         } else {
+00606                                 ep->desc_cnt = ep->pkt_cnt;
+00607                         }
+00608                         dwc_otg_iso_ep_start_ddma_transfer(core_if, ep);
+00609                 } else {
+00610                         if (core_if->pti_enh_enable) {
+00611                                 dwc_otg_iso_ep_start_buf_transfer(core_if, ep);
+00612                         } else {
+00613                                 ep->cur_pkt_addr =
+00614                                     (ep->proc_buf_num) ? ep->xfer_buff1 : ep->
+00615                                     xfer_buff0;
+00616                                 ep->cur_pkt_dma_addr =
+00617                                     (ep->proc_buf_num) ? ep->dma_addr1 : ep->
+00618                                     dma_addr0;
+00619                                 dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
+00620                         }
+00621                 }
+00622         } else {
+00623                 ep->cur_pkt_addr =
+00624                     (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0;
+00625                 ep->cur_pkt_dma_addr =
+00626                     (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0;
+00627                 dwc_otg_iso_ep_start_frm_transfer(core_if, ep);
+00628         }
+00629 }
+00630 
+00641 void dwc_otg_iso_ep_stop_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+00642 {
+00643         depctl_data_t depctl = {.d32 = 0 };
+00644         volatile uint32_t *addr;
+00645 
+00646         if (ep->is_in == 1) {
+00647                 addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
+00648         } else {
+00649                 addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
+00650         }
+00651 
+00652         /* disable the ep */
+00653         depctl.d32 = dwc_read_reg32(addr);
+00654 
+00655         depctl.b.epdis = 1;
+00656         depctl.b.snak = 1;
+00657 
+00658         dwc_write_reg32(addr, depctl.d32);
+00659 
+00660         if (core_if->dma_desc_enable &&
+00661             ep->iso_desc_addr && ep->iso_dma_desc_addr) {
+00662                 dwc_otg_ep_free_desc_chain(ep->iso_desc_addr,
+00663                                            ep->iso_dma_desc_addr,
+00664                                            ep->desc_cnt * 2);
+00665         }
+00666 
+00667         /* reset varibales */
+00668         ep->dma_addr0 = 0;
+00669         ep->dma_addr1 = 0;
+00670         ep->xfer_buff0 = 0;
+00671         ep->xfer_buff1 = 0;
+00672         ep->data_per_frame = 0;
+00673         ep->data_pattern_frame = 0;
+00674         ep->sync_frame = 0;
+00675         ep->buf_proc_intrvl = 0;
+00676         ep->bInterval = 0;
+00677         ep->proc_buf_num = 0;
+00678         ep->pkt_per_frm = 0;
+00679         ep->pkt_per_frm = 0;
+00680         ep->desc_cnt = 0;
+00681         ep->iso_desc_addr = 0;
+00682         ep->iso_dma_desc_addr = 0;
+00683 }
+00684 
+00685 int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
+00686                              uint8_t * buf0, uint8_t * buf1, dwc_dma_t dma0,
+00687                              dwc_dma_t dma1, int sync_frame, int dp_frame,
+00688                              int data_per_frame, int start_frame,
+00689                              int buf_proc_intrvl, void *req_handle,
+00690                              int atomic_alloc)
+00691 {
+00692         dwc_otg_pcd_ep_t *ep;
+00693         uint64_t flags = 0;
+00694         dwc_ep_t *dwc_ep;
+00695         int32_t frm_data;
+00696         dsts_data_t dsts;
+00697         dwc_otg_core_if_t *core_if;
+00698 
+00699         ep = get_ep_from_handle(pcd, ep_handle);
+00700 
+00701         if (!ep->desc || ep->dwc_ep.num == 0) {
+00702                 DWC_WARN("bad ep\n");
+00703                 return -DWC_E_INVALID;
+00704         }
+00705 
+00706         DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
+00707         core_if = GET_CORE_IF(pcd);
+00708         dwc_ep = &ep->dwc_ep;
+00709 
+00710         if (ep->iso_req_handle) {
+00711                 DWC_WARN("ISO request in progress\n");
+00712         }
+00713 
+00714         dwc_ep->dma_addr0 = dma0;
+00715         dwc_ep->dma_addr1 = dma1;
+00716 
+00717         dwc_ep->xfer_buff0 = buf0;
+00718         dwc_ep->xfer_buff1 = buf1;
+00719 
+00720         dwc_ep->data_per_frame = data_per_frame;
+00721 
+00723         dwc_ep->data_pattern_frame = dp_frame;
+00724         dwc_ep->sync_frame = sync_frame;
+00725 
+00726         dwc_ep->buf_proc_intrvl = buf_proc_intrvl;
+00727 
+00728         dwc_ep->bInterval = 1 << (ep->desc->bInterval - 1);
+00729 
+00730         dwc_ep->proc_buf_num = 0;
+00731 
+00732         dwc_ep->pkt_per_frm = 0;
+00733         frm_data = ep->dwc_ep.data_per_frame;
+00734         while (frm_data > 0) {
+00735                 dwc_ep->pkt_per_frm++;
+00736                 frm_data -= ep->dwc_ep.maxpacket;
+00737         }
+00738 
+00739         dsts.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
+00740 
+00741         if (start_frame == -1) {
+00742                 dwc_ep->next_frame = dsts.b.soffn + 1;
+00743                 if (dwc_ep->bInterval != 1) {
+00744                         dwc_ep->next_frame =
+00745                             dwc_ep->next_frame + (dwc_ep->bInterval - 1 -
+00746                                                   dwc_ep->next_frame %
+00747                                                   dwc_ep->bInterval);
+00748                 }
+00749         } else {
+00750                 dwc_ep->next_frame = start_frame;
+00751         }
+00752 
+00753         if (!core_if->pti_enh_enable) {
+00754                 dwc_ep->pkt_cnt =
+00755                     dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
+00756                     dwc_ep->bInterval;
+00757         } else {
+00758                 dwc_ep->pkt_cnt =
+00759                     (dwc_ep->data_per_frame *
+00760                      (dwc_ep->buf_proc_intrvl / dwc_ep->bInterval)
+00761                      - 1 + dwc_ep->maxpacket) / dwc_ep->maxpacket;
+00762         }
+00763 
+00764         if (core_if->dma_desc_enable) {
+00765                 dwc_ep->desc_cnt =
+00766                     dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm /
+00767                     dwc_ep->bInterval;
+00768         }
+00769 
+00770         if (atomic_alloc) {
+00771                 dwc_ep->pkt_info =
+00772                     dwc_alloc_atomic(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
+00773         } else {
+00774                 dwc_ep->pkt_info =
+00775                     dwc_alloc(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
+00776         }
+00777         if (!dwc_ep->pkt_info) {
+00778                 DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+00779                 return -DWC_E_NO_MEMORY;
+00780         }
+00781         if (core_if->pti_enh_enable) {
+00782                 dwc_memset(dwc_ep->pkt_info, 0,
+00783                            sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt);
+00784         }
+00785 
+00786         dwc_ep->cur_pkt = 0;
+00787         ep->iso_req_handle = req_handle;
+00788 
+00789         DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+00790         dwc_otg_iso_ep_start_transfer(core_if, dwc_ep);
+00791         return 0;
+00792 }
+00793 
+00794 int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
+00795                             void *req_handle)
+00796 {
+00797         uint64_t flags = 0;
+00798         dwc_otg_pcd_ep_t *ep;
+00799         dwc_ep_t *dwc_ep;
+00800 
+00801         ep = get_ep_from_handle(pcd, ep_handle);
+00802         if (!ep || !ep->desc || ep->dwc_ep.num == 0) {
+00803                 DWC_WARN("bad ep\n");
+00804                 return -DWC_E_INVALID;
+00805         }
+00806         dwc_ep = &ep->dwc_ep;
+00807 
+00808         dwc_otg_iso_ep_stop_transfer(GET_CORE_IF(pcd), dwc_ep);
+00809 
+00810         dwc_free(dwc_ep->pkt_info);
+00811         DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
+00812         if (ep->iso_req_handle != req_handle) {
+00813                 DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+00814                 return -DWC_E_INVALID;
+00815         }
+00816 
+00817         DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+00818 
+00819         ep->iso_req_handle = 0;
+00820         return 0;
+00821 }
+00822 
+00830 void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
+00831                              void *req_handle)
+00832 {
+00833         int i;
+00834         dwc_ep_t *dwc_ep;
+00835 
+00836         dwc_ep = &ep->dwc_ep;
+00837 
+00838         DWC_SPINUNLOCK(ep->pcd->lock);
+00839         pcd->fops->isoc_complete(pcd, ep->priv, ep->iso_req_handle,
+00840                                  dwc_ep->proc_buf_num ^ 0x1);
+00841         DWC_SPINLOCK(ep->pcd->lock);
+00842 
+00843         for (i = 0; i < dwc_ep->pkt_cnt; ++i) {
+00844                 dwc_ep->pkt_info[i].status = 0;
+00845                 dwc_ep->pkt_info[i].offset = 0;
+00846                 dwc_ep->pkt_info[i].length = 0;
+00847         }
+00848 }
+00849 
+00850 int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd, void *ep_handle,
+00851                                      void *iso_req_handle)
+00852 {
+00853         dwc_otg_pcd_ep_t *ep;
+00854         dwc_ep_t *dwc_ep;
+00855 
+00856         ep = get_ep_from_handle(pcd, ep_handle);
+00857         dwc_ep = &ep->dwc_ep;
+00858 
+00859         return dwc_ep->pkt_cnt;
+00860 }
+00861 
+00862 void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd, void *ep_handle,
+00863                                        void *iso_req_handle, int packet,
+00864                                        int *status, int *actual, int *offset)
+00865 {
+00866         dwc_otg_pcd_ep_t *ep;
+00867         dwc_ep_t *dwc_ep;
+00868 
+00869         ep = get_ep_from_handle(pcd, ep_handle);
+00870         dwc_ep = &ep->dwc_ep;
+00871 
+00872         *status = dwc_ep->pkt_info[packet].status;
+00873         *actual = dwc_ep->pkt_info[packet].length;
+00874         *offset = dwc_ep->pkt_info[packet].offset;
+00875 }
+00876 
+00877 #endif                          /* DWC_EN_ISOC */
+00878 
+00879 static void dwc_otg_pcd_init_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * pcd_ep,
+00880                                 uint32_t is_in, uint32_t ep_num)
+00881 {
+00882         /* Init EP structure */
+00883         pcd_ep->desc = 0;
+00884         pcd_ep->pcd = pcd;
+00885         pcd_ep->stopped = 1;
+00886         pcd_ep->queue_sof = 0;
+00887 
+00888         /* Init DWC ep structure */
+00889         pcd_ep->dwc_ep.is_in = is_in;
+00890         pcd_ep->dwc_ep.num = ep_num;
+00891         pcd_ep->dwc_ep.active = 0;
+00892         pcd_ep->dwc_ep.tx_fifo_num = 0;
+00893         /* Control until ep is actvated */
+00894         pcd_ep->dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
+00895         pcd_ep->dwc_ep.maxpacket = MAX_PACKET_SIZE;
+00896         pcd_ep->dwc_ep.dma_addr = 0;
+00897         pcd_ep->dwc_ep.start_xfer_buff = 0;
+00898         pcd_ep->dwc_ep.xfer_buff = 0;
+00899         pcd_ep->dwc_ep.xfer_len = 0;
+00900         pcd_ep->dwc_ep.xfer_count = 0;
+00901         pcd_ep->dwc_ep.sent_zlp = 0;
+00902         pcd_ep->dwc_ep.total_len = 0;
+00903         pcd_ep->dwc_ep.desc_addr = 0;
+00904         pcd_ep->dwc_ep.dma_desc_addr = 0;
+00905         DWC_CIRCLEQ_INIT(&pcd_ep->queue);
+00906 }
+00907 
+00911 static void dwc_otg_pcd_reinit(dwc_otg_pcd_t * pcd)
+00912 {
+00913         int i;
+00914         uint32_t hwcfg1;
+00915         dwc_otg_pcd_ep_t *ep;
+00916         int in_ep_cntr, out_ep_cntr;
+00917         uint32_t num_in_eps = (GET_CORE_IF(pcd))->dev_if->num_in_eps;
+00918         uint32_t num_out_eps = (GET_CORE_IF(pcd))->dev_if->num_out_eps;
+00919 
+00923         ep = &pcd->ep0;
+00924         dwc_otg_pcd_init_ep(pcd, ep, 0, 0);
+00925 
+00926         in_ep_cntr = 0;
+00927         hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 3;
+00928         for (i = 1; in_ep_cntr < num_in_eps; i++) {
+00929                 if ((hwcfg1 & 0x1) == 0) {
+00930                         dwc_otg_pcd_ep_t *ep = &pcd->in_ep[in_ep_cntr];
+00931                         in_ep_cntr++;
+00937                         dwc_otg_pcd_init_ep(pcd, ep, 1 /* IN */ , i);
+00938 
+00939                         DWC_CIRCLEQ_INIT(&ep->queue);
+00940                 }
+00941                 hwcfg1 >>= 2;
+00942         }
+00943 
+00944         out_ep_cntr = 0;
+00945         hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 2;
+00946         for (i = 1; out_ep_cntr < num_out_eps; i++) {
+00947                 if ((hwcfg1 & 0x1) == 0) {
+00948                         dwc_otg_pcd_ep_t *ep = &pcd->out_ep[out_ep_cntr];
+00949                         out_ep_cntr++;
+00955                         dwc_otg_pcd_init_ep(pcd, ep, 0 /* OUT */ , i);
+00956                         DWC_CIRCLEQ_INIT(&ep->queue);
+00957                 }
+00958                 hwcfg1 >>= 2;
+00959         }
+00960 
+00961         pcd->ep0state = EP0_DISCONNECT;
+00962         pcd->ep0.dwc_ep.maxpacket = MAX_EP0_SIZE;
+00963         pcd->ep0.dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL;
+00964 }
+00965 
+00970 static void srp_timeout(void *ptr)
+00971 {
+00972         gotgctl_data_t gotgctl;
+00973         dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
+00974         volatile uint32_t *addr = &core_if->core_global_regs->gotgctl;
+00975 
+00976         gotgctl.d32 = dwc_read_reg32(addr);
+00977 
+00978         core_if->srp_timer_started = 0;
+00979 
+00980         if ((core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS) &&
+00981             (core_if->core_params->i2c_enable)) {
+00982                 DWC_PRINTF("SRP Timeout\n");
+00983 
+00984                 if ((core_if->srp_success) && (gotgctl.b.bsesvld)) {
+00985                         if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) {
+00986                                 core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->
+00987                                                                p);
+00988                         }
+00989 
+00990                         /* Clear Session Request */
+00991                         gotgctl.d32 = 0;
+00992                         gotgctl.b.sesreq = 1;
+00993                         dwc_modify_reg32(&core_if->core_global_regs->gotgctl,
+00994                                          gotgctl.d32, 0);
+00995 
+00996                         core_if->srp_success = 0;
+00997                 } else {
+00998                         __DWC_ERROR("Device not connected/responding\n");
+00999                         gotgctl.b.sesreq = 0;
+01000                         dwc_write_reg32(addr, gotgctl.d32);
+01001                 }
+01002         } else if (gotgctl.b.sesreq) {
+01003                 DWC_PRINTF("SRP Timeout\n");
+01004 
+01005                 __DWC_ERROR("Device not connected/responding\n");
+01006                 gotgctl.b.sesreq = 0;
+01007                 dwc_write_reg32(addr, gotgctl.d32);
+01008         } else {
+01009                 DWC_PRINTF(" SRP GOTGCTL=%0x\n", gotgctl.d32);
+01010         }
+01011 }
+01012 
+01017 extern void start_next_request(dwc_otg_pcd_ep_t * ep);
+01018 
+01019 static void start_xfer_tasklet_func(void *data)
+01020 {
+01021         dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
+01022         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+01023 
+01024         int i;
+01025         depctl_data_t diepctl;
+01026 
+01027         DWC_DEBUGPL(DBG_PCDV, "Start xfer tasklet\n");
+01028 
+01029         diepctl.d32 = dwc_read_reg32(&core_if->dev_if->in_ep_regs[0]->diepctl);
+01030 
+01031         if (pcd->ep0.queue_sof) {
+01032                 pcd->ep0.queue_sof = 0;
+01033                 start_next_request(&pcd->ep0);
+01034                 // break;
+01035         }
+01036 
+01037         for (i = 0; i < core_if->dev_if->num_in_eps; i++) {
+01038                 depctl_data_t diepctl;
+01039                 diepctl.d32 =
+01040                     dwc_read_reg32(&core_if->dev_if->in_ep_regs[i]->diepctl);
+01041 
+01042                 if (pcd->in_ep[i].queue_sof) {
+01043                         pcd->in_ep[i].queue_sof = 0;
+01044                         start_next_request(&pcd->in_ep[i]);
+01045                         // break;
+01046                 }
+01047         }
+01048 
+01049         return;
+01050 }
+01051 
+01056 dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if)
+01057 {
+01058         dwc_otg_pcd_t *pcd = 0;
+01059         dwc_otg_dev_if_t *dev_if;
+01060 
+01061         /*
+01062          * Allocate PCD structure
+01063          */
+01064         pcd = dwc_alloc(sizeof(dwc_otg_pcd_t));
+01065 
+01066         if (pcd == 0) {
+01067                 return NULL;
+01068         }
+01069 
+01070         pcd->lock = DWC_SPINLOCK_ALLOC();
+01071         pcd->core_if = core_if;
+01072         if (!pcd->lock) {
+01073                 DWC_ERROR("Could not allocate lock for pcd");
+01074                 dwc_free(pcd);
+01075                 return NULL;
+01076         }
+01077         dev_if = core_if->dev_if;
+01078 
+01079         if (core_if->hwcfg4.b.ded_fifo_en) {
+01080                 DWC_PRINTF("Dedicated Tx FIFOs mode\n");
+01081         } else {
+01082                 DWC_PRINTF("Shared Tx FIFO mode\n");
+01083         }
+01084 
+01085         /*
+01086          * Initialized the Core for Device mode.
+01087          */
+01088         if (dwc_otg_is_device_mode(core_if)) {
+01089                 dwc_otg_core_dev_init(core_if);
+01090         }
+01091 
+01092         /*
+01093          * Register the PCD Callbacks.
+01094          */
+01095         dwc_otg_cil_register_pcd_callbacks(core_if, &pcd_callbacks, pcd);
+01096 
+01097         /*
+01098          * Initialize the DMA buffer for SETUP packets
+01099          */
+01100         if (GET_CORE_IF(pcd)->dma_enable) {
+01101                 pcd->setup_pkt =
+01102                     dwc_dma_alloc(sizeof(*pcd->setup_pkt) * 5,
+01103                                   &pcd->setup_pkt_dma_handle);
+01104                 if (pcd->setup_pkt == 0) {
+01105                         dwc_free(pcd);
+01106                         return NULL;
+01107                 }
+01108 
+01109                 pcd->status_buf =
+01110                     dwc_dma_alloc(sizeof(uint16_t),
+01111                                   &pcd->status_buf_dma_handle);
+01112                 if (pcd->status_buf == 0) {
+01113                         dwc_dma_free(sizeof(*pcd->setup_pkt) * 5,
+01114                                      pcd->setup_pkt, pcd->setup_pkt_dma_handle);
+01115                         dwc_free(pcd);
+01116                         return NULL;
+01117                 }
+01118 
+01119                 if (GET_CORE_IF(pcd)->dma_desc_enable) {
+01120                         dev_if->setup_desc_addr[0] =
+01121                             dwc_otg_ep_alloc_desc_chain(&dev_if->
+01122                                                         dma_setup_desc_addr[0],
+01123                                                         1);
+01124                         dev_if->setup_desc_addr[1] =
+01125                             dwc_otg_ep_alloc_desc_chain(&dev_if->
+01126                                                         dma_setup_desc_addr[1],
+01127                                                         1);
+01128                         dev_if->in_desc_addr =
+01129                             dwc_otg_ep_alloc_desc_chain(&dev_if->
+01130                                                         dma_in_desc_addr, 1);
+01131                         dev_if->out_desc_addr =
+01132                             dwc_otg_ep_alloc_desc_chain(&dev_if->
+01133                                                         dma_out_desc_addr, 1);
+01134 
+01135                         if (dev_if->setup_desc_addr[0] == 0
+01136                             || dev_if->setup_desc_addr[1] == 0
+01137                             || dev_if->in_desc_addr == 0
+01138                             || dev_if->out_desc_addr == 0) {
+01139 
+01140                                 if (dev_if->out_desc_addr)
+01141                                         dwc_otg_ep_free_desc_chain(dev_if->
+01142                                                                    out_desc_addr,
+01143                                                                    dev_if->
+01144                                                                    dma_out_desc_addr,
+01145                                                                    1);
+01146                                 if (dev_if->in_desc_addr)
+01147                                         dwc_otg_ep_free_desc_chain(dev_if->
+01148                                                                    in_desc_addr,
+01149                                                                    dev_if->
+01150                                                                    dma_in_desc_addr,
+01151                                                                    1);
+01152                                 if (dev_if->setup_desc_addr[1])
+01153                                         dwc_otg_ep_free_desc_chain(dev_if->
+01154                                                                    setup_desc_addr
+01155                                                                    [1],
+01156                                                                    dev_if->
+01157                                                                    dma_setup_desc_addr
+01158                                                                    [1], 1);
+01159                                 if (dev_if->setup_desc_addr[0])
+01160                                         dwc_otg_ep_free_desc_chain(dev_if->
+01161                                                                    setup_desc_addr
+01162                                                                    [0],
+01163                                                                    dev_if->
+01164                                                                    dma_setup_desc_addr
+01165                                                                    [0], 1);
+01166 
+01167                                 dwc_dma_free(sizeof(*pcd->setup_pkt) * 5,
+01168                                              pcd->setup_pkt,
+01169                                              pcd->setup_pkt_dma_handle);
+01170                                 dwc_dma_free(sizeof(*pcd->status_buf),
+01171                                              pcd->status_buf,
+01172                                              pcd->status_buf_dma_handle);
+01173 
+01174                                 dwc_free(pcd);
+01175 
+01176                                 return NULL;
+01177                         }
+01178                 }
+01179         } else {
+01180                 pcd->setup_pkt = dwc_alloc(sizeof(*pcd->setup_pkt) * 5);
+01181                 if (pcd->setup_pkt == 0) {
+01182                         dwc_free(pcd);
+01183                         return NULL;
+01184                 }
+01185 
+01186                 pcd->status_buf = dwc_alloc(sizeof(uint16_t));
+01187                 if (pcd->status_buf == 0) {
+01188                         dwc_free(pcd->setup_pkt);
+01189                         dwc_free(pcd);
+01190                         return NULL;
+01191                 }
+01192         }
+01193 
+01194         dwc_otg_pcd_reinit(pcd);
+01195 
+01196         /* Allocate the cfi object for the PCD */
+01197 #ifdef DWC_UTE_CFI
+01198         pcd->cfi = dwc_alloc(sizeof(cfiobject_t));
+01199         if (NULL == pcd->cfi)
+01200                 return NULL;
+01201         if (init_cfi(pcd->cfi)) {
+01202                 CFI_INFO("%s: Failed to init the CFI object\n", __func__);
+01203                 return NULL;
+01204         }
+01205 #endif
+01206 
+01207         /* Initialize tasklets */
+01208         pcd->start_xfer_tasklet = DWC_TASK_ALLOC(start_xfer_tasklet_func, pcd);
+01209         pcd->test_mode_tasklet = DWC_TASK_ALLOC(do_test_mode, pcd);
+01210         /* Initialize timer */
+01211         pcd->srp_timer = DWC_TIMER_ALLOC("SRP TIMER", srp_timeout, core_if);
+01212         return pcd;
+01213 }
+01214 
+01215 void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd)
+01216 {
+01217         dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
+01218 
+01219         if (GET_CORE_IF(pcd)->dma_enable) {
+01220                 dwc_dma_free(sizeof(*pcd->setup_pkt) * 5, pcd->setup_pkt,
+01221                              pcd->setup_pkt_dma_handle);
+01222                 dwc_dma_free(sizeof(uint16_t), pcd->status_buf,
+01223                              pcd->status_buf_dma_handle);
+01224                 if (GET_CORE_IF(pcd)->dma_desc_enable) {
+01225                         dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[0],
+01226                                                    dev_if->
+01227                                                    dma_setup_desc_addr[0], 1);
+01228                         dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[1],
+01229                                                    dev_if->
+01230                                                    dma_setup_desc_addr[1], 1);
+01231                         dwc_otg_ep_free_desc_chain(dev_if->in_desc_addr,
+01232                                                    dev_if->dma_in_desc_addr, 1);
+01233                         dwc_otg_ep_free_desc_chain(dev_if->out_desc_addr,
+01234                                                    dev_if->dma_out_desc_addr,
+01235                                                    1);
+01236                 }
+01237         } else {
+01238                 dwc_free(pcd->setup_pkt);
+01239                 dwc_free(pcd->status_buf);
+01240         }
+01241         DWC_SPINLOCK_FREE(pcd->lock);
+01242         DWC_TASK_FREE(pcd->start_xfer_tasklet);
+01243         DWC_TASK_FREE(pcd->test_mode_tasklet);
+01244         DWC_TIMER_FREE(pcd->srp_timer);
+01245 
+01246 /* Release the CFI object's dynamic memory */
+01247 #ifdef DWC_UTE_CFI
+01248         if (pcd->cfi->ops.release) {
+01249                 pcd->cfi->ops.release(pcd->cfi);
+01250         }
+01251 #endif
+01252 
+01253         dwc_free(pcd);
+01254 }
+01255 
+01256 uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd)
+01257 {
+01258         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+01259 
+01260         if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) ||
+01261             ((core_if->hwcfg2.b.hs_phy_type == 2) &&
+01262              (core_if->hwcfg2.b.fs_phy_type == 1) &&
+01263              (core_if->core_params->ulpi_fs_ls))) {
+01264                 return 0;
+01265         }
+01266 
+01267         return 1;
+01268 }
+01269 
+01270 uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd)
+01271 {
+01272         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+01273         gusbcfg_data_t usbcfg = {.d32 = 0 };
+01274 
+01275         usbcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->gusbcfg);
+01276         if (!usbcfg.b.srpcap || !usbcfg.b.hnpcap) {
+01277                 return 0;
+01278         }
+01279 
+01280         return 1;
+01281 }
+01282 
+01287 static uint32_t assign_tx_fifo(dwc_otg_core_if_t * core_if)
+01288 {
+01289         uint32_t TxMsk = 1;
+01290         int i;
+01291 
+01292         for (i = 0; i < core_if->hwcfg4.b.num_in_eps; ++i) {
+01293                 if ((TxMsk & core_if->tx_msk) == 0) {
+01294                         core_if->tx_msk |= TxMsk;
+01295                         return i + 1;
+01296                 }
+01297                 TxMsk <<= 1;
+01298         }
+01299         return 0;
+01300 }
+01301 
+01306 static uint32_t assign_perio_tx_fifo(dwc_otg_core_if_t * core_if)
+01307 {
+01308         uint32_t PerTxMsk = 1;
+01309         int i;
+01310         for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; ++i) {
+01311                 if ((PerTxMsk & core_if->p_tx_msk) == 0) {
+01312                         core_if->p_tx_msk |= PerTxMsk;
+01313                         return i + 1;
+01314                 }
+01315                 PerTxMsk <<= 1;
+01316         }
+01317         return 0;
+01318 }
+01319 
+01324 static void release_perio_tx_fifo(dwc_otg_core_if_t * core_if,
+01325                                   uint32_t fifo_num)
+01326 {
+01327         core_if->p_tx_msk =
+01328             (core_if->p_tx_msk & (1 << (fifo_num - 1))) ^ core_if->p_tx_msk;
+01329 }
+01330 
+01335 static void release_tx_fifo(dwc_otg_core_if_t * core_if, uint32_t fifo_num)
+01336 {
+01337         core_if->tx_msk =
+01338             (core_if->tx_msk & (1 << (fifo_num - 1))) ^ core_if->tx_msk;
+01339 }
+01340 
+01341 int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
+01342                           const uint8_t * ep_desc, void *usb_ep)
+01343 {
+01344         int num, dir;
+01345         dwc_otg_pcd_ep_t *ep = 0;
+01346         const usb_endpoint_descriptor_t *desc;
+01347         uint64_t flags;
+01348         int retval = 0;
+01349 
+01350         desc = (const usb_endpoint_descriptor_t *)ep_desc;
+01351 
+01352         if (!desc) {
+01353                 pcd->ep0.priv = usb_ep;
+01354                 ep = &pcd->ep0;
+01355                 retval = -DWC_E_INVALID;
+01356                 goto out;
+01357         }
+01358 
+01359         num = UE_GET_ADDR(desc->bEndpointAddress);
+01360         dir = UE_GET_DIR(desc->bEndpointAddress);
+01361 
+01362         if (!desc->wMaxPacketSize) {
+01363                 DWC_WARN("bad maxpacketsize\n");
+01364                 retval = -DWC_E_INVALID;
+01365                 goto out;
+01366         }
+01367 
+01368         if (dir == UE_DIR_IN) {
+01369                 ep = &pcd->in_ep[num - 1];
+01370         } else {
+01371                 ep = &pcd->out_ep[num - 1];
+01372         }
+01373 
+01374         DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
+01375 
+01376         ep->desc = desc;
+01377         ep->priv = usb_ep;
+01378 
+01379         /*
+01380          * Activate the EP
+01381          */
+01382         ep->stopped = 0;
+01383 
+01384         ep->dwc_ep.is_in = (dir == UE_DIR_IN);
+01385         ep->dwc_ep.maxpacket = UGETW(desc->wMaxPacketSize);
+01386 
+01387         ep->dwc_ep.type = desc->bmAttributes & UE_XFERTYPE;
+01388 
+01389         if (ep->dwc_ep.is_in) {
+01390                 if (!GET_CORE_IF(pcd)->en_multiple_tx_fifo) {
+01391                         ep->dwc_ep.tx_fifo_num = 0;
+01392 
+01393                         if (ep->dwc_ep.type == UE_ISOCHRONOUS) {
+01394                                 /*
+01395                                  * if ISOC EP then assign a Periodic Tx FIFO.
+01396                                  */
+01397                                 ep->dwc_ep.tx_fifo_num =
+01398                                     assign_perio_tx_fifo(GET_CORE_IF(pcd));
+01399                         }
+01400                 } else {
+01401                         /*
+01402                          * if Dedicated FIFOs mode is on then assign a Tx FIFO.
+01403                          */
+01404                         ep->dwc_ep.tx_fifo_num =
+01405                             assign_tx_fifo(GET_CORE_IF(pcd));
+01406 
+01407                 }
+01408         }
+01409         /* Set initial data PID. */
+01410         if (ep->dwc_ep.type == UE_BULK) {
+01411                 ep->dwc_ep.data_pid_start = 0;
+01412         }
+01413 
+01414         /* Alloc DMA Descriptors */
+01415         if (GET_CORE_IF(pcd)->dma_desc_enable) {
+01416                 if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
+01417                         ep->dwc_ep.desc_addr =
+01418                             dwc_otg_ep_alloc_desc_chain(&ep->dwc_ep.
+01419                                                         dma_desc_addr,
+01420                                                         MAX_DMA_DESC_CNT);
+01421                         if (!ep->dwc_ep.desc_addr) {
+01422                                 DWC_WARN("%s, can't allocate DMA descriptor\n",
+01423                                          __func__);
+01424                                 retval = -DWC_E_SHUTDOWN;
+01425                                 DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+01426                                 goto out;
+01427                         }
+01428                 }
+01429         }
+01430 
+01431         DWC_DEBUGPL(DBG_PCD, "Activate %s: type=%d, mps=%d desc=%p\n",
+01432                     (ep->dwc_ep.is_in ? "IN" : "OUT"),
+01433                     ep->dwc_ep.type, ep->dwc_ep.maxpacket, ep->desc);
+01434 
+01435         dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
+01436 
+01437 #ifdef DWC_UTE_CFI
+01438         if (pcd->cfi->ops.ep_enable) {
+01439                 pcd->cfi->ops.ep_enable(pcd->cfi, pcd, ep);
+01440         }
+01441 #endif
+01442 
+01443         DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+01444 
+01445       out:
+01446         return retval;
+01447 }
+01448 
+01449 int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle)
+01450 {
+01451         dwc_otg_pcd_ep_t *ep;
+01452         uint64_t flags;
+01453         dwc_otg_dev_dma_desc_t *desc_addr;
+01454         dwc_dma_t dma_desc_addr;
+01455 
+01456         ep = get_ep_from_handle(pcd, ep_handle);
+01457 
+01458         if (!ep || !ep->desc) {
+01459                 DWC_DEBUGPL(DBG_PCD, "%s, %d %s not enabled\n", __func__,
+01460                             ep->dwc_ep.num, ep->dwc_ep.is_in ? "IN" : "OUT");
+01461                 return -DWC_E_INVALID;
+01462         }
+01463 
+01464         DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
+01465 
+01466         dwc_otg_request_nuke(ep);
+01467 
+01468         dwc_otg_ep_deactivate(GET_CORE_IF(pcd), &ep->dwc_ep);
+01469         ep->desc = 0;
+01470         ep->stopped = 1;
+01471 
+01472         if (ep->dwc_ep.is_in) {
+01473                 dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
+01474                 release_perio_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
+01475                 release_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num);
+01476         }
+01477 
+01478         /* Free DMA Descriptors */
+01479         if (GET_CORE_IF(pcd)->dma_desc_enable) {
+01480                 if (ep->dwc_ep.type != UE_ISOCHRONOUS) {
+01481                         desc_addr = ep->dwc_ep.desc_addr;
+01482                         dma_desc_addr = ep->dwc_ep.dma_desc_addr;
+01483 
+01484                         /* Cannot call dma_free_coherent() with IRQs disabled */
+01485                         DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+01486                         dwc_otg_ep_free_desc_chain(desc_addr, dma_desc_addr,
+01487                                                    MAX_DMA_DESC_CNT);
+01488 
+01489                         goto out_unlocked;
+01490                 }
+01491         }
+01492 
+01493         DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+01494 
+01495       out_unlocked:
+01496         DWC_DEBUGPL(DBG_PCD, "%d %s disabled\n", ep->dwc_ep.num,
+01497                     ep->dwc_ep.is_in ? "IN" : "OUT");
+01498         return 0;
+01499 
+01500 }
+01501 
+01502 int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
+01503                          uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen,
+01504                          int zero, void *req_handle, int atomic_alloc)
+01505 {
+01506         int prevented = 0;
+01507         uint64_t flags;
+01508         dwc_otg_pcd_request_t *req;
+01509         dwc_otg_pcd_ep_t *ep;
+01510         uint32_t max_transfer;
+01511 
+01512         ep = get_ep_from_handle(pcd, ep_handle);
+01513         if ((!ep->desc && ep->dwc_ep.num != 0)) {
+01514                 DWC_WARN("bad ep\n");
+01515                 return -DWC_E_INVALID;
+01516         }
+01517 
+01518         if (atomic_alloc) {
+01519                 req = dwc_alloc_atomic(sizeof(*req));
+01520         } else {
+01521                 req = dwc_alloc(sizeof(*req));
+01522         }
+01523 
+01524         if (!req) {
+01525                 return -DWC_E_NO_MEMORY;
+01526         }
+01527         DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry);
+01528         if (!GET_CORE_IF(pcd)->core_params->opt) {
+01529                 if (ep->dwc_ep.num != 0) {
+01530                         DWC_ERROR("queue req %p, len %d buf %p\n",
+01531                                   req_handle, buflen, buf);
+01532                 }
+01533         }
+01534 
+01535         req->buf = buf;
+01536         req->dma = dma_buf;
+01537         req->length = buflen;
+01538         req->sent_zlp = zero;
+01539         req->priv = req_handle;
+01540 
+01541         DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
+01542 
+01543         /*
+01544          * For EP0 IN without premature status, zlp is required?
+01545          */
+01546         if (ep->dwc_ep.num == 0 && ep->dwc_ep.is_in) {
+01547                 DWC_DEBUGPL(DBG_PCDV, "%d-OUT ZLP\n", ep->dwc_ep.num);
+01548                 //_req->zero = 1;
+01549         }
+01550 
+01551         /* Start the transfer */
+01552         if (DWC_CIRCLEQ_EMPTY(&ep->queue) && !ep->stopped) {
+01553                 /* EP0 Transfer? */
+01554                 if (ep->dwc_ep.num == 0) {
+01555                         switch (pcd->ep0state) {
+01556                         case EP0_IN_DATA_PHASE:
+01557                                 DWC_DEBUGPL(DBG_PCD,
+01558                                             "%s ep0: EP0_IN_DATA_PHASE\n",
+01559                                             __func__);
+01560                                 break;
+01561 
+01562                         case EP0_OUT_DATA_PHASE:
+01563                                 DWC_DEBUGPL(DBG_PCD,
+01564                                             "%s ep0: EP0_OUT_DATA_PHASE\n",
+01565                                             __func__);
+01566                                 if (pcd->request_config) {
+01567                                         /* Complete STATUS PHASE */
+01568                                         ep->dwc_ep.is_in = 1;
+01569                                         pcd->ep0state = EP0_IN_STATUS_PHASE;
+01570                                 }
+01571                                 break;
+01572 
+01573                         case EP0_IN_STATUS_PHASE:
+01574                                 DWC_DEBUGPL(DBG_PCD,
+01575                                             "%s ep0: EP0_IN_STATUS_PHASE\n",
+01576                                             __func__);
+01577                                 break;
+01578 
+01579                         default:
+01580                                 DWC_DEBUGPL(DBG_ANY, "ep0: odd state %d\n",
+01581                                             pcd->ep0state);
+01582                                 DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+01583                                 return -DWC_E_SHUTDOWN;
+01584                         }
+01585 
+01586                         ep->dwc_ep.dma_addr = dma_buf;
+01587                         ep->dwc_ep.start_xfer_buff = buf;
+01588                         ep->dwc_ep.xfer_buff = buf;
+01589                         ep->dwc_ep.xfer_len = buflen;
+01590                         ep->dwc_ep.xfer_count = 0;
+01591                         ep->dwc_ep.sent_zlp = 0;
+01592                         ep->dwc_ep.total_len = ep->dwc_ep.xfer_len;
+01593 
+01594                         if (zero) {
+01595                                 if ((ep->dwc_ep.xfer_len %
+01596                                      ep->dwc_ep.maxpacket == 0)
+01597                                     && (ep->dwc_ep.xfer_len != 0)) {
+01598                                         ep->dwc_ep.sent_zlp = 1;
+01599                                 }
+01600 
+01601                         }
+01602 
+01603                         dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd),
+01604                                                    &ep->dwc_ep);
+01605                 }               // non-ep0 endpoints
+01606                 else {
+01607 #ifdef DWC_UTE_CFI
+01608                         if (ep->dwc_ep.buff_mode != BM_STANDARD) {
+01609                                 /* store the request length */
+01610                                 ep->dwc_ep.cfi_req_len = buflen;
+01611                                 pcd->cfi->ops.build_descriptors(pcd->cfi, pcd,
+01612                                                                 ep, req);
+01613                 } else {
+01614 #endif
+01615                                 max_transfer =
+01616                                     GET_CORE_IF(ep->pcd)->core_params->
+01617                                     max_transfer_size;
+01618 
+01619                         /* Setup and start the Transfer */
+01620                         ep->dwc_ep.dma_addr = dma_buf;
+01621                         ep->dwc_ep.start_xfer_buff = buf;
+01622                         ep->dwc_ep.xfer_buff = buf;
+01623                         ep->dwc_ep.xfer_len = 0;
+01624                         ep->dwc_ep.xfer_count = 0;
+01625                         ep->dwc_ep.sent_zlp = 0;
+01626                         ep->dwc_ep.total_len = buflen;
+01627 
+01628                         ep->dwc_ep.maxxfer = max_transfer;
+01629                         if (GET_CORE_IF(pcd)->dma_desc_enable) {
+01630                                         uint32_t out_max_xfer =
+01631                                             DDMA_MAX_TRANSFER_SIZE -
+01632                                             (DDMA_MAX_TRANSFER_SIZE % 4);
+01633                                 if (ep->dwc_ep.is_in) {
+01634                                         if (ep->dwc_ep.maxxfer >
+01635                                             DDMA_MAX_TRANSFER_SIZE) {
+01636                                                 ep->dwc_ep.maxxfer =
+01637                                                     DDMA_MAX_TRANSFER_SIZE;
+01638                                         }
+01639                                 } else {
+01640                                                 if (ep->dwc_ep.maxxfer >
+01641                                                     out_max_xfer) {
+01642                                                 ep->dwc_ep.maxxfer =
+01643                                                     out_max_xfer;
+01644                                         }
+01645                                 }
+01646                         }
+01647                         if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
+01648                                 ep->dwc_ep.maxxfer -=
+01649                                             (ep->dwc_ep.maxxfer %
+01650                                              ep->dwc_ep.maxpacket);
+01651                         }
+01652 
+01653                         if (zero) {
+01654                                 if ((ep->dwc_ep.total_len %
+01655                                              ep->dwc_ep.maxpacket == 0)
+01656                                             && (ep->dwc_ep.total_len != 0)) {
+01657                                         ep->dwc_ep.sent_zlp = 1;
+01658                                 }
+01659                         }
+01660 #ifdef DWC_UTE_CFI
+01661                         }
+01662 #endif
+01663                         dwc_otg_ep_start_transfer(GET_CORE_IF(pcd),
+01664                                                   &ep->dwc_ep);
+01665                 }
+01666         }
+01667 
+01668         if ((req != 0) || prevented) {
+01669                 ++pcd->request_pending;
+01670                 DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry);
+01671                 if (ep->dwc_ep.is_in && ep->stopped
+01672                     && !(GET_CORE_IF(pcd)->dma_enable)) {
+01674                         diepmsk_data_t diepmsk = {.d32 = 0 };
+01675                         diepmsk.b.intktxfemp = 1;
+01676                         if (GET_CORE_IF(pcd)->multiproc_int_enable) {
+01677                                 dwc_modify_reg32(&GET_CORE_IF(pcd)->dev_if->
+01678                                                  dev_global_regs->
+01679                                                  diepeachintmsk[ep->dwc_ep.num],
+01680                                                  0, diepmsk.d32);
+01681                         } else {
+01682                                 dwc_modify_reg32(&GET_CORE_IF(pcd)->dev_if->
+01683                                                  dev_global_regs->diepmsk, 0,
+01684                                                  diepmsk.d32);
+01685                         }
+01686 
+01687                 }
+01688         }
+01689 
+01690         DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+01691 
+01692         return 0;
+01693 }
+01694 int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
+01695                            void *req_handle)
+01696 {
+01697         uint64_t flags;
+01698         dwc_otg_pcd_request_t *req;
+01699         dwc_otg_pcd_ep_t *ep;
+01700 
+01701         ep = get_ep_from_handle(pcd, ep_handle);
+01702         if (!ep->desc && ep->dwc_ep.num != 0) {
+01703                 DWC_WARN("bad argument\n");
+01704                 return -DWC_E_INVALID;
+01705         }
+01706 
+01707         DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
+01708 
+01709         /* make sure it's actually queued on this endpoint */
+01710         DWC_CIRCLEQ_FOREACH(req, &ep->queue, queue_entry) {
+01711                 if (req->priv == (void *)req_handle) {
+01712                         break;
+01713                 }
+01714         }
+01715 
+01716         if (req->priv != (void *)req_handle) {
+01717                 DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+01718                 return -DWC_E_INVALID;
+01719         }
+01720 
+01721         if (!DWC_CIRCLEQ_EMPTY_ENTRY(req, queue_entry)) {
+01722                 dwc_otg_request_done(ep, req, -DWC_E_RESTART);
+01723         } else {
+01724                 req = 0;
+01725         }
+01726 
+01727         DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+01728 
+01729         return req ? 0 : -DWC_E_SHUTDOWN;
+01730 
+01731 }
+01732 
+01733 int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value)
+01734 {
+01735         dwc_otg_pcd_ep_t *ep;
+01736         uint64_t flags;
+01737         int retval = 0;
+01738 
+01739         ep = get_ep_from_handle(pcd, ep_handle);
+01740 
+01741         if ((!ep->desc && ep != &pcd->ep0) ||
+01742             (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) {
+01743                 DWC_WARN("%s, bad ep\n", __func__);
+01744                 return -DWC_E_INVALID;
+01745         }
+01746 
+01747         DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
+01748         if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
+01749                 DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num,
+01750                          ep->dwc_ep.is_in ? "IN" : "OUT");
+01751                 retval = -DWC_E_AGAIN;
+01752         } else if (value == 0) {
+01753                 dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
+01754         } else if (value == 1) {
+01755                 if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) {
+01756                         dtxfsts_data_t txstatus;
+01757                         fifosize_data_t txfifosize;
+01758 
+01759                         txfifosize.d32 =
+01760                             dwc_read_reg32(&GET_CORE_IF(pcd)->core_global_regs->
+01761                                            dptxfsiz_dieptxf[ep->dwc_ep.
+01762                                                             tx_fifo_num]);
+01763                         txstatus.d32 =
+01764                             dwc_read_reg32(&GET_CORE_IF(pcd)->dev_if->
+01765                                            in_ep_regs[ep->dwc_ep.num]->dtxfsts);
+01766 
+01767                         if (txstatus.b.txfspcavail < txfifosize.b.depth) {
+01768                                 DWC_WARN("%s() Data In Tx Fifo\n", __func__);
+01769                                 retval = -DWC_E_AGAIN;
+01770                         } else {
+01771                                 if (ep->dwc_ep.num == 0) {
+01772                                         pcd->ep0state = EP0_STALL;
+01773                                 }
+01774 
+01775                                 ep->stopped = 1;
+01776                                 dwc_otg_ep_set_stall(GET_CORE_IF(pcd),
+01777                                                      &ep->dwc_ep);
+01778                         }
+01779                 } else {
+01780                         if (ep->dwc_ep.num == 0) {
+01781                                 pcd->ep0state = EP0_STALL;
+01782                         }
+01783 
+01784                         ep->stopped = 1;
+01785                         dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
+01786                 }
+01787         } else if (value == 2) {
+01788                 ep->dwc_ep.stall_clear_flag = 0;
+01789         } else if (value == 3) {
+01790                 ep->dwc_ep.stall_clear_flag = 1;
+01791         }
+01792 
+01793         DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+01794 
+01795         return retval;
+01796 }
+01797 
+01801 void dwc_otg_pcd_rem_wkup_from_suspend(dwc_otg_pcd_t * pcd, int set)
+01802 {
+01803         dctl_data_t dctl = { 0 };
+01804         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+01805         dsts_data_t dsts;
+01806 
+01807         dsts.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
+01808         if (!dsts.b.suspsts) {
+01809                 DWC_WARN("Remote wakeup while is not in suspend state\n");
+01810         }
+01811         /* Check if DEVICE_REMOTE_WAKEUP feature enabled */
+01812         if (pcd->remote_wakeup_enable) {
+01813                 if (set) {
+01814                         dctl.b.rmtwkupsig = 1;
+01815                         dwc_modify_reg32(&core_if->dev_if->dev_global_regs->
+01816                                          dctl, 0, dctl.d32);
+01817                         DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
+01818                         dwc_mdelay(2);
+01819                         dwc_modify_reg32(&core_if->dev_if->dev_global_regs->
+01820                                          dctl, dctl.d32, 0);
+01821                         DWC_DEBUGPL(DBG_PCD, "Clear Remote Wakeup\n");
+01822                 }
+01823         } else {
+01824                 DWC_DEBUGPL(DBG_PCD, "Remote Wakeup is disabled\n");
+01825         }
+01826 }
+01827 
+01828 #ifdef CONFIG_USB_DWC_OTG_LPM
+01829 
+01832 void dwc_otg_pcd_rem_wkup_from_sleep(dwc_otg_pcd_t * pcd, int set)
+01833 {
+01834         glpmcfg_data_t lpmcfg;
+01835         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+01836 
+01837         lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
+01838 
+01839         /* Check if we are in L1 state */
+01840         if (!lpmcfg.b.prt_sleep_sts) {
+01841                 DWC_DEBUGPL(DBG_PCD, "Device is not in sleep state\n");
+01842                 return;
+01843         }
+01844 
+01845         /* Check if host allows remote wakeup */
+01846         if (!lpmcfg.b.rem_wkup_en) {
+01847                 DWC_DEBUGPL(DBG_PCD, "Host does not allow remote wakeup\n");
+01848                 return;
+01849         }
+01850 
+01851         /* Check if Resume OK */
+01852         if (!lpmcfg.b.sleep_state_resumeok) {
+01853                 DWC_DEBUGPL(DBG_PCD, "Sleep state resume is not OK\n");
+01854                 return;
+01855         }
+01856 
+01857         lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg);
+01858         lpmcfg.b.en_utmi_sleep = 0;
+01859         lpmcfg.b.hird_thres &= (~(1 << 4));
+01860         dwc_write_reg32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32);
+01861 
+01862         if (set) {
+01863                 dctl_data_t dctl = {.d32 = 0 };
+01864                 dctl.b.rmtwkupsig = 1;
+01865                 /* Set RmtWkUpSig bit to start remote wakup signaling.
+01866                  * Hardware will automatically clear this bit.
+01867                  */
+01868                 dwc_modify_reg32(&core_if->dev_if->dev_global_regs->dctl,
+01869                                  0, dctl.d32);
+01870                 DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n");
+01871         }
+01872 
+01873 }
+01874 #endif
+01875 
+01879 void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set)
+01880 {
+01881         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+01882         if (dwc_otg_is_device_mode(core_if)) {
+01883 #ifdef CONFIG_USB_DWC_OTG_LPM
+01884                 if (core_if->lx_state == DWC_OTG_L1) {
+01885                         dwc_otg_pcd_rem_wkup_from_sleep(pcd, set);
+01886                 } else {
+01887 #endif
+01888                         dwc_otg_pcd_rem_wkup_from_suspend(pcd, set);
+01889 #ifdef CONFIG_USB_DWC_OTG_LPM
+01890                 }
+01891 #endif
+01892         }
+01893         return;
+01894 }
+01895 
+01896 int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd)
+01897 {
+01898         dsts_data_t dsts;
+01899         gotgctl_data_t gotgctl;
+01900         uint64_t flags;
+01901 
+01902         DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags);
+01903 
+01904         /*
+01905          * This function starts the Protocol if no session is in progress. If
+01906          * a session is already in progress, but the device is suspended,
+01907          * remote wakeup signaling is started.
+01908          */
+01909 
+01910         /* Check if valid session */
+01911         gotgctl.d32 =
+01912             dwc_read_reg32(&(GET_CORE_IF(pcd)->core_global_regs->gotgctl));
+01913         if (gotgctl.b.bsesvld) {
+01914                 /* Check if suspend state */
+01915                 dsts.d32 =
+01916                     dwc_read_reg32(&
+01917                                    (GET_CORE_IF(pcd)->dev_if->dev_global_regs->
+01918                                     dsts));
+01919                 if (dsts.b.suspsts) {
+01920                         dwc_otg_pcd_remote_wakeup(pcd, 1);
+01921                 }
+01922         } else {
+01923                 dwc_otg_pcd_initiate_srp(pcd);
+01924         }
+01925 
+01926         DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags);
+01927         return 0;
+01928 
+01929 }
+01930 
+01937 void dwc_otg_pcd_start_srp_timer(dwc_otg_pcd_t * pcd)
+01938 {
+01939         GET_CORE_IF(pcd)->srp_timer_started = 1;
+01940         DWC_TIMER_SCHEDULE(pcd->srp_timer, 6000 /* 6 secs */ );
+01941 }
+01942 
+01943 void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd)
+01944 {
+01945         uint32_t *addr =
+01946             (uint32_t *) & (GET_CORE_IF(pcd)->core_global_regs->gotgctl);
+01947         gotgctl_data_t mem;
+01948         gotgctl_data_t val;
+01949 
+01950         val.d32 = dwc_read_reg32(addr);
+01951         if (val.b.sesreq) {
+01952                 DWC_ERROR("Session Request Already active!\n");
+01953                 return;
+01954         }
+01955 
+01956         DWC_INFO("Session Request Initated\n"); //NOTICE
+01957         mem.d32 = dwc_read_reg32(addr);
+01958         mem.b.sesreq = 1;
+01959         dwc_write_reg32(addr, mem.d32);
+01960 
+01961         /* Start the SRP timer */
+01962         dwc_otg_pcd_start_srp_timer(pcd);
+01963         return;
+01964 }
+01965 
+01966 int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd)
+01967 {
+01968         return dwc_otg_get_frame_number(GET_CORE_IF(pcd));
+01969 }
+01970 
+01971 int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd)
+01972 {
+01973         return GET_CORE_IF(pcd)->core_params->lpm_enable;
+01974 }
+01975 
+01976 uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd)
+01977 {
+01978         return pcd->b_hnp_enable;
+01979 }
+01980 
+01981 uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd)
+01982 {
+01983         return pcd->a_hnp_support;
+01984 }
+01985 
+01986 uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd)
+01987 {
+01988         return pcd->a_alt_hnp_support;
+01989 }
+01990 
+01991 int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd)
+01992 {
+01993         return pcd->remote_wakeup_enable;
+01994 }
+01995 
+01996 #endif                          /* DWC_HOST_ONLY */
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd_8c.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd_8c.html new file mode 100644 index 000000000000..bbd10a6a8033 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd_8c.html @@ -0,0 +1,1343 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_pcd.c File Reference + + + + + + +

dwc_otg_pcd.c File Reference

This file implements PCD Core. More... +

+#include "dwc_otg_pcd.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Functions

+static dwc_otg_pcd_ep_tget_ep_from_handle (dwc_otg_pcd_t *pcd, void *handle)
void dwc_otg_request_done (dwc_otg_pcd_ep_t *ep, dwc_otg_pcd_request_t *req, int32_t status)
 This function completes a request.
+void dwc_otg_request_nuke (dwc_otg_pcd_ep_t *ep)
 This function terminates all the requsts in the EP request queue.
void dwc_otg_pcd_start (dwc_otg_pcd_t *pcd, const struct dwc_otg_pcd_function_ops *fops)
 Call this to bind the function driver to the PCD Core.
static int32_t dwc_otg_pcd_start_cb (void *p)
 PCD Callback function for initializing the PCD when switching to device mode.
+uint8_t * cfiw_ep_alloc_buffer (dwc_otg_pcd_t *pcd, void *pep, dwc_dma_t *addr, size_t buflen, int flags)
 CFI-specific buffer allocation function for EP.
static int32_t dwc_otg_pcd_resume_cb (void *p)
 PCD Callback function for notifying the PCD when resuming from suspend.
static int32_t dwc_otg_pcd_suspend_cb (void *p)
 PCD Callback function for notifying the PCD device is suspended.
static int32_t dwc_otg_pcd_stop_cb (void *p)
 PCD Callback function for stopping the PCD when switching to Host mode.
+dwc_otg_dev_dma_desc_tdwc_otg_ep_alloc_desc_chain (uint32_t *dma_desc_addr, uint32_t count)
 This function allocates a DMA Descriptor chain for the Endpoint buffer to be used for a transfer to/from the specified endpoint.
+void dwc_otg_ep_free_desc_chain (dwc_otg_dev_dma_desc_t *desc_addr, uint32_t dma_desc_addr, uint32_t count)
 This function frees a DMA Descriptor chain that was allocated by ep_alloc_desc.
void dwc_otg_iso_ep_start_ddma_transfer (dwc_otg_core_if_t *core_if, dwc_ep_t *dwc_ep)
 This function initializes a descriptor chain for Isochronous transfer.
void dwc_otg_iso_ep_start_buf_transfer (dwc_otg_core_if_t *core_if, dwc_ep_t *ep)
 This function initializes a descriptor chain for Isochronous transfer.
static void dwc_otg_iso_ep_start_transfer (dwc_otg_core_if_t *core_if, dwc_ep_t *ep)
 This function does the setup for a data transfer for an EP and starts the transfer.
void dwc_otg_iso_ep_stop_transfer (dwc_otg_core_if_t *core_if, dwc_ep_t *ep)
 This function does the setup for a data transfer for an EP and starts the transfer.
int dwc_otg_pcd_iso_ep_start (dwc_otg_pcd_t *pcd, void *ep_handle, uint8_t *buf0, uint8_t *buf1, dwc_dma_t dma0, dwc_dma_t dma1, int sync_frame, int dp_frame, int data_per_frame, int start_frame, int buf_proc_intrvl, void *req_handle, int atomic_alloc)
 Start isochronous transfers on the endpoint referenced by ep_handle.
int dwc_otg_pcd_iso_ep_stop (dwc_otg_pcd_t *pcd, void *ep_handle, void *req_handle)
 Stop ISOC transfers on endpoint referenced by ep_handle.
void dwc_otg_iso_buffer_done (dwc_otg_pcd_t *pcd, dwc_otg_pcd_ep_t *ep, void *req_handle)
 This function is used for perodical data exchnage between PCD and gadget drivers.
int dwc_otg_pcd_get_iso_packet_count (dwc_otg_pcd_t *pcd, void *ep_handle, void *iso_req_handle)
 Get ISOC packet count.
void dwc_otg_pcd_get_iso_packet_params (dwc_otg_pcd_t *pcd, void *ep_handle, void *iso_req_handle, int packet, int *status, int *actual, int *offset)
 Get ISOC packet status.
+static void dwc_otg_pcd_init_ep (dwc_otg_pcd_t *pcd, dwc_otg_pcd_ep_t *pcd_ep, uint32_t is_in, uint32_t ep_num)
static void dwc_otg_pcd_reinit (dwc_otg_pcd_t *pcd)
 Initialise ep's.
static void srp_timeout (void *ptr)
 This function is called when the SRP timer expires.
+void start_next_request (dwc_otg_pcd_ep_t *ep)
 Tasklet.
+static void start_xfer_tasklet_func (void *data)
dwc_otg_pcd_tdwc_otg_pcd_init (dwc_otg_core_if_t *core_if)
 Call this function to get pointer on dwc_otg_pcd_t, this pointer will be used for all PCD API functions.
void dwc_otg_pcd_remove (dwc_otg_pcd_t *pcd)
 Frees PCD allocated by dwc_otg_pcd_init.
+uint32_t dwc_otg_pcd_is_dualspeed (dwc_otg_pcd_t *pcd)
 This function returns whether device is dualspeed.
+uint32_t dwc_otg_pcd_is_otg (dwc_otg_pcd_t *pcd)
 This function returns whether device is otg.
+static uint32_t assign_tx_fifo (dwc_otg_core_if_t *core_if)
 This function assigns periodic Tx FIFO to an periodic EP in shared Tx FIFO mode.
+static uint32_t assign_perio_tx_fifo (dwc_otg_core_if_t *core_if)
 This function assigns periodic Tx FIFO to an periodic EP in shared Tx FIFO mode.
+static void release_perio_tx_fifo (dwc_otg_core_if_t *core_if, uint32_t fifo_num)
 This function releases periodic Tx FIFO in shared Tx FIFO mode.
+static void release_tx_fifo (dwc_otg_core_if_t *core_if, uint32_t fifo_num)
 This function releases periodic Tx FIFO in shared Tx FIFO mode.
int dwc_otg_pcd_ep_enable (dwc_otg_pcd_t *pcd, const uint8_t *ep_desc, void *usb_ep)
 Enables an endpoint for use.
int dwc_otg_pcd_ep_disable (dwc_otg_pcd_t *pcd, void *ep_handle)
 Disable the endpoint referenced by ep_handle.
int dwc_otg_pcd_ep_queue (dwc_otg_pcd_t *pcd, void *ep_handle, uint8_t *buf, dwc_dma_t dma_buf, uint32_t buflen, int zero, void *req_handle, int atomic_alloc)
 Queue a data transfer request on the endpoint referenced by ep_handle.
int dwc_otg_pcd_ep_dequeue (dwc_otg_pcd_t *pcd, void *ep_handle, void *req_handle)
 De-queue the specified data transfer that has not yet completed.
int dwc_otg_pcd_ep_halt (dwc_otg_pcd_t *pcd, void *ep_handle, int value)
 Halt (STALL) an endpoint or clear it.
+void dwc_otg_pcd_rem_wkup_from_suspend (dwc_otg_pcd_t *pcd, int set)
 This function initiates remote wakeup of the host from suspend state.
+void dwc_otg_pcd_remote_wakeup (dwc_otg_pcd_t *pcd, int set)
 Starts remote wakeup signaling.
int dwc_otg_pcd_wakeup (dwc_otg_pcd_t *pcd)
 This function starts the SRP Protocol if no session is in progress.
void dwc_otg_pcd_start_srp_timer (dwc_otg_pcd_t *pcd)
 Start the SRP timer to detect when the SRP does not complete within 6 seconds.
+void dwc_otg_pcd_initiate_srp (dwc_otg_pcd_t *pcd)
 Initiate SRP.
+int dwc_otg_pcd_get_frame_number (dwc_otg_pcd_t *pcd)
 This function returns current frame number.
+int dwc_otg_pcd_is_lpm_enabled (dwc_otg_pcd_t *pcd)
 This function returns 1 if LPM support is enabled, and 0 otherwise.
+uint32_t get_b_hnp_enable (dwc_otg_pcd_t *pcd)
 These functions allow to get hnp parameters.
+uint32_t get_a_hnp_support (dwc_otg_pcd_t *pcd)
+uint32_t get_a_alt_hnp_support (dwc_otg_pcd_t *pcd)
+int dwc_otg_pcd_get_rmwkup_enable (dwc_otg_pcd_t *pcd)
 This function returns 1 if remote wakeup is allowed and 0, otherwise.

Variables

static dwc_otg_cil_callbacks_t pcd_callbacks
 PCD Callback structure for handling mode switching.
+


Detailed Description

+This file implements PCD Core. +

+All code in this file is portable and don't use any OS specific functions. PCD Core provides Interface, defined in <dwc_otg_pcd_if.h> header file, which can be used to implement OS specific PCD interface.

+An important function of the PCD is managing interrupts generated by the DWC_otg controller. The implementation of the DWC_otg device mode interrupt service routines is in dwc_otg_pcd_intr.c.

+

Todo:
Add Device Mode test modes (Test J mode, Test K mode, etc).

+Does it work when the request size is greater than DEPTSIZ transfer size

+ +

+Definition in file dwc_otg_pcd.c.


Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_request_done (dwc_otg_pcd_ep_t ep,
dwc_otg_pcd_request_t req,
int32_t  status 
)
+
+
+ +

+This function completes a request. +

+It call's the request call back. +

+Definition at line 78 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_pcd_start (dwc_otg_pcd_t pcd,
const struct dwc_otg_pcd_function_ops fops 
)
+
+
+ +

+Call this to bind the function driver to the PCD Core. +

+

Parameters:
+ + + +
pcd Pointer on dwc_otg_pcd_t returned by dwc_otg_pcd_init function.
fops The Function Driver Ops data structure containing pointers to all callbacks.
+
+ +

+Definition at line 117 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + +
static int32_t dwc_otg_pcd_start_cb (void *  p  )  [static]
+
+
+ +

+PCD Callback function for initializing the PCD when switching to device mode. +

+

Parameters:
+ + +
p void pointer to the dwc_otg_pcd_t
+
+ +

+Definition at line 129 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + +
static int32_t dwc_otg_pcd_resume_cb (void *  p  )  [static]
+
+
+ +

+PCD Callback function for notifying the PCD when resuming from suspend. +

+

Parameters:
+ + +
p void pointer to the dwc_otg_pcd_t
+
+ +

+Definition at line 163 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + +
static int32_t dwc_otg_pcd_suspend_cb (void *  p  )  [static]
+
+
+ +

+PCD Callback function for notifying the PCD device is suspended. +

+

Parameters:
+ + +
p void pointer to the dwc_otg_pcd_t
+
+ +

+Definition at line 187 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + +
static int32_t dwc_otg_pcd_stop_cb (void *  p  )  [static]
+
+
+ +

+PCD Callback function for stopping the PCD when switching to Host mode. +

+

Parameters:
+ + +
p void pointer to the dwc_otg_pcd_t
+
+ +

+Definition at line 204 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_iso_ep_start_ddma_transfer (dwc_otg_core_if_t core_if,
dwc_ep_t dwc_ep 
)
+
+
+ +

+This function initializes a descriptor chain for Isochronous transfer. +

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
dwc_ep The EP to start the transfer on.
+
+ +

+Allocate descriptors for double buffering

+ISO OUT EP

+Buffer 0 descriptors setup

+Buffer 1 descriptors setup

+Write dma_ad into DOEPDMA register

+ISO IN EP

+Buffer 0 descriptors setup

+Buffer 1 descriptors setup

+Write dma_ad into diepdma register

+Enable endpoint, clear nak +

+Definition at line 254 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_iso_ep_start_buf_transfer (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function initializes a descriptor chain for Isochronous transfer. +

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to start the transfer on.
+
+ +

+Enable endpoint, clear nak +

+Definition at line 517 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static void dwc_otg_iso_ep_start_transfer (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
) [static]
+
+
+ +

+This function does the setup for a data transfer for an EP and starts the transfer. +

+For an IN transfer, the packets will be loaded into the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are unloaded from the Rx FIFO in the ISR. the ISR.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to start the transfer on.
+
+ +

+Definition at line 598 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_iso_ep_stop_transfer (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function does the setup for a data transfer for an EP and starts the transfer. +

+For an IN transfer, the packets will be loaded into the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are unloaded from the Rx FIFO in the ISR. the ISR.

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to start the transfer on.
+
+ +

+Definition at line 641 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_pcd_iso_ep_start (dwc_otg_pcd_t pcd,
void *  ep_handle,
uint8_t *  buf0,
uint8_t *  buf1,
dwc_dma_t  dma0,
dwc_dma_t  dma1,
int  sync_frame,
int  dp_frame,
int  data_per_frame,
int  start_frame,
int  buf_proc_intrvl,
void *  req_handle,
int  atomic_alloc 
)
+
+
+ +

+Start isochronous transfers on the endpoint referenced by ep_handle. +

+For isochronous transfers duble buffering is used. After processing each of buffers comlete callback will be called with status for each transaction.

+

Parameters:
+ + + + + + + + + + + + + + +
pcd The PCD
ep_handle The handle of the endpoint
buf0 The virtual address of first data buffer
buf1 The virtual address of second data buffer
dma0 The DMA address of first data buffer
dma1 The DMA address of second data buffer
sync_frame Data pattern frame number
dp_frame Data size for pattern frame
data_per_frame Data size for regular frame
start_frame Frame number to start transfers, if -1 then start transfers ASAP.
buf_proc_intrvl Interval of ISOC Buffer processing
req_handle Handle of ISOC request
atomic_alloc Specefies whether to perform atomic allocation for internal data structures.
+
+Returns -DWC_E_NO_MEMORY if there is no enough memory. Returns -DWC_E_INVALID if incorrect arguments are passed to the function. Returns -DW_E_SHUTDOWN for any other error. Returns 0 on success +

+

Todo:
    +
  • pattern data support is to be implemented in the future
+
+ +

+Definition at line 685 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_pcd_iso_ep_stop (dwc_otg_pcd_t pcd,
void *  ep_handle,
void *  req_handle 
)
+
+
+ +

+Stop ISOC transfers on endpoint referenced by ep_handle. +

+

Parameters:
+ + + + +
pcd The PCD
ep_handle The handle of the endpoint
req_handle Handle of ISOC request
+
+Returns -DWC_E_INVALID if incorrect arguments are passed to the function Returns 0 on success +

+Definition at line 794 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_iso_buffer_done (dwc_otg_pcd_t pcd,
dwc_otg_pcd_ep_t ep,
void *  req_handle 
)
+
+
+ +

+This function is used for perodical data exchnage between PCD and gadget drivers. +

+for Isochronous EPs

+

    +
  • Every time a sync period completes this function is called to perform data exchange between PCD and gadget
+ +

+Definition at line 830 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_pcd_get_iso_packet_count (dwc_otg_pcd_t pcd,
void *  ep_handle,
void *  iso_req_handle 
)
+
+
+ +

+Get ISOC packet count. +

+

Parameters:
+ + + + +
pcd The PCD
ep_handle The handle of the endpoint
iso_req_handle 
+
+ +

+Definition at line 850 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_pcd_get_iso_packet_params (dwc_otg_pcd_t pcd,
void *  ep_handle,
void *  iso_req_handle,
int  packet,
int *  status,
int *  actual,
int *  offset 
)
+
+
+ +

+Get ISOC packet status. +

+

Parameters:
+ + + + + + + + +
pcd The PCD
ep_handle The handle of the endpoint
iso_req_handle Isochronoush request handle
packet Number of packet
status Out parameter for returning status
actual Out parameter for returning actual length
offset Out parameter for returning offset
+
+ +

+Definition at line 862 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + +
static void dwc_otg_pcd_reinit (dwc_otg_pcd_t pcd  )  [static]
+
+
+ +

+Initialise ep's. +

+ +

+Initialize the EP0 structure.

+

Todo:
NGS: Add direction to EP, based on contents of HWCFG1. Need a copy of HWCFG1 in pcd structure? sprintf(";r
+

+

Todo:
NGS: Add direction to EP, based on contents of HWCFG1. Need a copy of HWCFG1 in pcd structure? sprintf(";r
+ +

+Definition at line 911 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + +
static void srp_timeout (void *  ptr  )  [static]
+
+
+ +

+This function is called when the SRP timer expires. +

+The SRP should complete within 6 seconds. +

+Definition at line 970 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + +
dwc_otg_pcd_t* dwc_otg_pcd_init (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+Call this function to get pointer on dwc_otg_pcd_t, this pointer will be used for all PCD API functions. +

+

Parameters:
+ + +
core_if The DWC_OTG Core
+
+ +

+Definition at line 1056 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_pcd_remove (dwc_otg_pcd_t pcd  ) 
+
+
+ +

+Frees PCD allocated by dwc_otg_pcd_init. +

+

Parameters:
+ + +
pcd The PCD
+
+ +

+Definition at line 1215 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_pcd_ep_enable (dwc_otg_pcd_t pcd,
const uint8_t *  ep_desc,
void *  ep_handle 
)
+
+
+ +

+Enables an endpoint for use. +

+This function enables an endpoint in the PCD. The endpoint is described by the ep_desc which has the same format as a USB ep descriptor. The ep_handle parameter is used to refer to the endpoint from other API functions and in callbacks. Normally this should be called after a SET_CONFIGURATION/SET_INTERFACE to configure the core for that interface.

+Returns -DWC_E_INVALID if invalid parameters were passed. Returns -DWC_E_SHUTDOWN if any other error ocurred. Returns 0 on success.

+

Parameters:
+ + + + +
pcd The PCD
ep_desc Endpoint descriptor
ep_handle Handle on endpoint, that will be used to identify endpoint.
+
+ +

+Definition at line 1341 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_pcd_ep_disable (dwc_otg_pcd_t pcd,
void *  ep_handle 
)
+
+
+ +

+Disable the endpoint referenced by ep_handle. +

+Returns -DWC_E_INVALID if invalid parameters were passed. Returns -DWC_E_SHUTDOWN if any other error ocurred. Returns 0 on success. +

+Definition at line 1449 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_pcd_ep_queue (dwc_otg_pcd_t pcd,
void *  ep_handle,
uint8_t *  buf,
dwc_dma_t  dma_buf,
uint32_t  buflen,
int  zero,
void *  req_handle,
int  atomic_alloc 
)
+
+
+ +

+Queue a data transfer request on the endpoint referenced by ep_handle. +

+After the transfer is completes, the complete callback will be called with the request status.

+

Parameters:
+ + + + + + + + + +
pcd The PCD
ep_handle The handle of the endpoint
buf The buffer for the data
dma_buf The DMA buffer for the data
buflen The length of the data transfer
zero Specifies whether to send zero length last packet.
req_handle Set this handle to any value to use to reference this request in the ep_dequeue function or from the complete callback
atomic_alloc If driver need to perform atomic allocations for internal data structures.
+
+Returns -DWC_E_INVALID if invalid parameters were passed. Returns -DWC_E_SHUTDOWN if any other error ocurred. Returns 0 on success. +

+

Todo:
NGS Create a function for this.
+ +

+Definition at line 1502 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_pcd_ep_dequeue (dwc_otg_pcd_t pcd,
void *  ep_handle,
void *  req_handle 
)
+
+
+ +

+De-queue the specified data transfer that has not yet completed. +

+Returns -DWC_E_INVALID if invalid parameters were passed. Returns -DWC_E_SHUTDOWN if any other error ocurred. Returns 0 on success. +

+Definition at line 1694 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_pcd_ep_halt (dwc_otg_pcd_t pcd,
void *  ep_handle,
int  value 
)
+
+
+ +

+Halt (STALL) an endpoint or clear it. +

+Returns -DWC_E_INVALID if invalid parameters were passed. Returns -DWC_E_SHUTDOWN if any other error ocurred. Returns -DWC_E_AGAIN if the STALL cannot be sent and must be tried again later Returns 0 on success. +

+Definition at line 1733 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + +
int dwc_otg_pcd_wakeup (dwc_otg_pcd_t pcd  ) 
+
+
+ +

+This function starts the SRP Protocol if no session is in progress. +

+If a session is already in progress, but the device is suspended, remote wakeup signaling is started. +

+Definition at line 1896 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_pcd_start_srp_timer (dwc_otg_pcd_t pcd  ) 
+
+
+ +

+Start the SRP timer to detect when the SRP does not complete within 6 seconds. +

+

Parameters:
+ + +
pcd the pcd structure.
+
+ +

+Definition at line 1937 of file dwc_otg_pcd.c. +

+

+


Variable Documentation

+ +
+ +
+ +

+Initial value:

 {
+        .start = dwc_otg_pcd_start_cb,
+        .stop = dwc_otg_pcd_stop_cb,
+        .suspend = dwc_otg_pcd_suspend_cb,
+        .resume_wakeup = dwc_otg_pcd_resume_cb,
+        .p = 0,                 
+}
+
PCD Callback structure for handling mode switching. +

+ +

+Definition at line 216 of file dwc_otg_pcd.c. +

+

+


Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd_8h-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd_8h-source.html new file mode 100644 index 000000000000..aabe3e08f248 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd_8h-source.html @@ -0,0 +1,171 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_pcd.h Source File + + + + + + +

dwc_otg_pcd.h

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.h $
+00003  * $Revision: #39 $
+00004  * $Date: 2008/12/16 $
+00005  * $Change: 1153731 $
+00006  *
+00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009  * otherwise expressly agreed to in writing between Synopsys and you.
+00010  *
+00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012  * any End User Software License Agreement or Agreement for Licensed Product
+00013  * with Synopsys or any supplement thereto. You are permitted to use and
+00014  * redistribute this Software in source and binary forms, with or without
+00015  * modification, provided that redistributions of source code must retain this
+00016  * notice. You may not view, use, disclose, copy or distribute this file or
+00017  * any information contained herein except pursuant to this license grant from
+00018  * Synopsys. If you do not agree with this notice, including the disclaimer
+00019  * below, then you are not authorized to use the Software.
+00020  *
+00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031  * DAMAGE.
+00032  * ========================================================================== */
+00033 #ifndef DWC_HOST_ONLY
+00034 #if !defined(__DWC_PCD_H__)
+00035 #define __DWC_PCD_H__
+00036 
+00037 #include "usb.h"
+00038 #include "dwc_otg_cil.h"
+00039 #include "dwc_otg_pcd_if.h"
+00040 struct cfiobject;
+00041 
+00058 #define DDMA_MAX_TRANSFER_SIZE 65535
+00059 
+00061 #define MAX_DMA_DESC_CNT 64
+00062 
+00066 #define GET_CORE_IF( _pcd ) (_pcd->core_if)
+00067 
+00071 typedef enum ep0_state {
+00072         EP0_DISCONNECT,         /* no host */
+00073         EP0_IDLE,
+00074         EP0_IN_DATA_PHASE,
+00075         EP0_OUT_DATA_PHASE,
+00076         EP0_IN_STATUS_PHASE,
+00077         EP0_OUT_STATUS_PHASE,
+00078         EP0_STALL,
+00079 } ep0state_e;
+00080 
+00082 struct dwc_otg_pcd;
+00083 
+00087 typedef struct usb_iso_request dwc_otg_pcd_iso_request_t;
+00088 
+00092 typedef struct dwc_otg_pcd_request {
+00093         void *priv;
+00094         void *buf;
+00095         dwc_dma_t dma;
+00096         uint32_t length;
+00097         uint32_t actual;
+00098         unsigned sent_zlp:1;
+00099 
+00100          DWC_CIRCLEQ_ENTRY(dwc_otg_pcd_request) queue_entry;
+00101 } dwc_otg_pcd_request_t;
+00102 
+00103 DWC_CIRCLEQ_HEAD(req_list, dwc_otg_pcd_request);
+00104 
+00109 typedef struct dwc_otg_pcd_ep {
+00111         const usb_endpoint_descriptor_t *desc;
+00112 
+00114         struct req_list queue;
+00115         unsigned stopped:1;
+00116         unsigned disabling:1;
+00117         unsigned dma:1;
+00118         unsigned queue_sof:1;
+00119 
+00120 #ifdef DWC_EN_ISOC
+00121 
+00122         void *iso_req_handle;
+00123 #endif                          //_EN_ISOC_
+00124 
+00126         dwc_ep_t dwc_ep;
+00127 
+00129         struct dwc_otg_pcd *pcd;
+00130 
+00131         void *priv;
+00132 } dwc_otg_pcd_ep_t;
+00133 
+00137 struct dwc_otg_pcd {
+00138         const struct dwc_otg_pcd_function_ops *fops;
+00140         dwc_otg_core_if_t *core_if;
+00142         ep0state_e ep0state;
+00144         unsigned ep0_pending:1;
+00146         unsigned request_config:1;
+00148         unsigned remote_wakeup_enable:1;
+00150         unsigned b_hnp_enable:1;
+00152         unsigned a_hnp_support:1;
+00154         unsigned a_alt_hnp_support:1;
+00156         unsigned request_pending;
+00157 
+00162         union {
+00163                 usb_device_request_t req;
+00164                 uint32_t d32[2];
+00165         } *setup_pkt;
+00166 
+00167         dwc_dma_t setup_pkt_dma_handle;
+00168 
+00170         uint16_t *status_buf;
+00171         dwc_dma_t status_buf_dma_handle;
+00172 
+00174         dwc_otg_pcd_ep_t ep0;
+00175 
+00177         dwc_otg_pcd_ep_t in_ep[MAX_EPS_CHANNELS - 1];
+00179         dwc_otg_pcd_ep_t out_ep[MAX_EPS_CHANNELS - 1];
+00181 //        unsigned      num_eps : 4;
+00182         dwc_spinlock_t *lock;
+00185         dwc_timer_t *srp_timer;
+00186 
+00190         dwc_tasklet_t *test_mode_tasklet;
+00191 
+00193         dwc_tasklet_t *start_xfer_tasklet;
+00194 
+00196         unsigned test_mode;
+00200 #ifdef DWC_UTE_CFI
+00201         struct cfiobject *cfi;
+00202 #endif
+00203 
+00204 };
+00205 
+00206 //FIXME this functions should be static, and this prototypes should be removed
+00207 extern void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep);
+00208 extern void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep,
+00209                                  dwc_otg_pcd_request_t * req, int32_t status);
+00210 
+00211 void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep,
+00212                              void *req_handle);
+00213 
+00214 extern void do_test_mode(void *data);
+00215 #endif
+00216 #endif                          /* DWC_HOST_ONLY */
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd_8h.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd_8h.html new file mode 100644 index 000000000000..7b122bb57d88 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd_8h.html @@ -0,0 +1,254 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_pcd.h File Reference + + + + + + +

dwc_otg_pcd.h File Reference

This file contains the structures, constants, and interfaces for the Perpherial Contoller Driver (PCD). More... +

+#include "usb.h"
+#include "dwc_otg_cil.h"
+#include "dwc_otg_pcd_if.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Structures

struct  dwc_otg_pcd_request
 DWC_otg request structure. More...
struct  dwc_otg_pcd_ep
 PCD EP structure. More...
struct  dwc_otg_pcd
 DWC_otg PCD Structure. More...

Defines

+#define __DWC_PCD_H__
+#define DDMA_MAX_TRANSFER_SIZE   65535
 Max Transfer size for any EP.
+#define MAX_DMA_DESC_CNT   64
 Max DMA Descriptor count for any EP.
+#define GET_CORE_IF(_pcd)   (_pcd->core_if)
 Get the pointer to the core_if from the pcd pointer.

Typedefs

+typedef enum ep0_state ep0state_e
 States of EP0.
+typedef usb_iso_request dwc_otg_pcd_iso_request_t
 DWC_otg iso request structure.
typedef dwc_otg_pcd_request dwc_otg_pcd_request_t
 DWC_otg request structure.
typedef dwc_otg_pcd_ep dwc_otg_pcd_ep_t
 PCD EP structure.

Enumerations

enum  ep0_state {
+  EP0_DISCONNECT, +EP0_IDLE, +EP0_IN_DATA_PHASE, +EP0_OUT_DATA_PHASE, +
+  EP0_IN_STATUS_PHASE, +EP0_OUT_STATUS_PHASE, +EP0_STALL +
+ }
 States of EP0.

Functions

DWC_CIRCLEQ_HEAD (req_list, dwc_otg_pcd_request)
+void dwc_otg_request_nuke (dwc_otg_pcd_ep_t *ep)
 This function terminates all the requsts in the EP request queue.
void dwc_otg_request_done (dwc_otg_pcd_ep_t *ep, dwc_otg_pcd_request_t *req, int32_t status)
 This function completes a request.
void dwc_otg_iso_buffer_done (dwc_otg_pcd_t *pcd, dwc_otg_pcd_ep_t *ep, void *req_handle)
 This function is used for perodical data exchnage between PCD and gadget drivers.
void do_test_mode (void *data)
 This function is called when the SET_FEATURE TEST_MODE Setup packet is sent from the host.
+


Detailed Description

+This file contains the structures, constants, and interfaces for the Perpherial Contoller Driver (PCD). +

+The Peripheral Controller Driver (PCD) for Linux will implement the Gadget API, so that the existing Gadget drivers can be used. For the Mass Storage Function driver the File-backed USB Storage Gadget (FBS) driver will be used. The FBS driver supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI), and Bulk-Only transports. +

+Definition in file dwc_otg_pcd.h.


Typedef Documentation

+ +
+
+ + + + +
typedef struct dwc_otg_pcd_request dwc_otg_pcd_request_t
+
+
+ +

+DWC_otg request structure. +

+This structure is a list of requests. +

+

+ +

+
+ + + + +
typedef struct dwc_otg_pcd_ep dwc_otg_pcd_ep_t
+
+
+ +

+PCD EP structure. +

+This structure describes an EP, there is an array of EPs in the PCD structure. +

+

+


Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_request_done (dwc_otg_pcd_ep_t ep,
dwc_otg_pcd_request_t req,
int32_t  status 
)
+
+
+ +

+This function completes a request. +

+It call's the request call back. +

+Definition at line 78 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_iso_buffer_done (dwc_otg_pcd_t pcd,
dwc_otg_pcd_ep_t ep,
void *  req_handle 
)
+
+
+ +

+This function is used for perodical data exchnage between PCD and gadget drivers. +

+for Isochronous EPs

+

    +
  • Every time a sync period completes this function is called to perform data exchange between PCD and gadget
+ +

+Definition at line 830 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + +
void do_test_mode (void *  data  ) 
+
+
+ +

+This function is called when the SET_FEATURE TEST_MODE Setup packet is sent from the host. +

+The Device Control register is written with the Test Mode bits set to the specified Test Mode. This is done as a tasklet so that the "Status" phase of the control transfer completes before transmitting the TEST packets.

+

Todo:
This has not been tested since the tasklet struct was put into the PCD struct!
+ +

+Definition at line 1284 of file dwc_otg_pcd_intr.c. +

+

+


Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__if_8h-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__if_8h-source.html new file mode 100644 index 000000000000..e8baf1de306a --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__if_8h-source.html @@ -0,0 +1,174 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_pcd_if.h Source File + + + + + + +

dwc_otg_pcd_if.h

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_if.h $
+00003  * $Revision: #6 $
+00004  * $Date: 2009/04/03 $
+00005  * $Change: 1225059 $
+00006  *
+00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009  * otherwise expressly agreed to in writing between Synopsys and you.
+00010  *
+00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012  * any End User Software License Agreement or Agreement for Licensed Product
+00013  * with Synopsys or any supplement thereto. You are permitted to use and
+00014  * redistribute this Software in source and binary forms, with or without
+00015  * modification, provided that redistributions of source code must retain this
+00016  * notice. You may not view, use, disclose, copy or distribute this file or
+00017  * any information contained herein except pursuant to this license grant from
+00018  * Synopsys. If you do not agree with this notice, including the disclaimer
+00019  * below, then you are not authorized to use the Software.
+00020  *
+00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031  * DAMAGE.
+00032  * ========================================================================== */
+00033 #ifndef DWC_HOST_ONLY
+00034 
+00035 #if !defined(__DWC_PCD_IF_H__)
+00036 #define __DWC_PCD_IF_H__
+00037 
+00038 #include "dwc_os.h"
+00039 #include "dwc_otg_core_if.h"
+00040 
+00045 struct dwc_otg_pcd;
+00046 typedef struct dwc_otg_pcd dwc_otg_pcd_t;
+00047 
+00049 #define MAX_EP0_SIZE    64
+00050 
+00051 #define MAX_PACKET_SIZE 1024
+00052 
+00061 typedef int (*dwc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
+00062                                     void *req_handle, int32_t status,
+00063                                     uint32_t actual);
+00071 typedef int (*dwc_isoc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle,
+00072                                          void *req_handle, int proc_buf_num);
+00081 typedef int (*dwc_setup_cb_t) (dwc_otg_pcd_t * pcd, uint8_t * bytes);
+00086 typedef int (*dwc_disconnect_cb_t) (dwc_otg_pcd_t * pcd);
+00088 typedef int (*dwc_connect_cb_t) (dwc_otg_pcd_t * pcd, int speed);
+00090 typedef int (*dwc_suspend_cb_t) (dwc_otg_pcd_t * pcd);
+00093 typedef int (*dwc_sleep_cb_t) (dwc_otg_pcd_t * pcd);
+00096 typedef int (*dwc_resume_cb_t) (dwc_otg_pcd_t * pcd);
+00100 typedef int (*dwc_hnp_params_changed_cb_t) (dwc_otg_pcd_t * pcd);
+00102 typedef int (*dwc_reset_cb_t) (dwc_otg_pcd_t * pcd);
+00103 
+00104 typedef int (*cfi_setup_cb_t) (dwc_otg_pcd_t * pcd, void *ctrl_req_bytes);
+00105 
+00107 struct dwc_otg_pcd_function_ops {
+00108         dwc_connect_cb_t connect;
+00109         dwc_disconnect_cb_t disconnect;
+00110         dwc_setup_cb_t setup;
+00111         dwc_completion_cb_t complete;
+00112         dwc_isoc_completion_cb_t isoc_complete;
+00113         dwc_suspend_cb_t suspend;
+00114         dwc_sleep_cb_t sleep;
+00115         dwc_resume_cb_t resume;
+00116         dwc_reset_cb_t reset;
+00117         dwc_hnp_params_changed_cb_t hnp_changed;
+00118         cfi_setup_cb_t cfi_setup;
+00119 };
+00130 extern dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if);
+00131 
+00136 extern void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd);
+00137 
+00143 extern void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd,
+00144                               const struct dwc_otg_pcd_function_ops *fops);
+00145 
+00161 extern int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd,
+00162                                  const uint8_t * ep_desc, void *ep_handle);
+00163 
+00169 extern int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle);
+00170 
+00189 extern int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle,
+00190                                 uint8_t * buf, dwc_dma_t dma_buf,
+00191                                 uint32_t buflen, int zero, void *req_handle,
+00192                                 int atomic_alloc);
+00193 
+00199 extern int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle,
+00200                                   void *req_handle);
+00201 
+00208 extern int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value);
+00209 
+00211 extern int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd);
+00212 
+00214 extern int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd);
+00215 
+00242 extern int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle,
+00243                                     uint8_t * buf0, uint8_t * buf1,
+00244                                     dwc_dma_t dma0, dwc_dma_t dma1,
+00245                                     int sync_frame, int dp_frame,
+00246                                     int data_per_frame, int start_frame,
+00247                                     int buf_proc_intrvl, void *req_handle,
+00248                                     int atomic_alloc);
+00249 
+00259 int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle,
+00260                             void *req_handle);
+00261 
+00273 extern void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd,
+00274                                               void *ep_handle,
+00275                                               void *iso_req_handle, int packet,
+00276                                               int *status, int *actual,
+00277                                               int *offset);
+00278 
+00285 extern int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd,
+00286                                             void *ep_handle,
+00287                                             void *iso_req_handle);
+00288 
+00293 extern int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd);
+00294 
+00296 extern int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd);
+00297 
+00299 extern int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd);
+00300 
+00302 extern void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd);
+00303 
+00305 extern void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set);
+00306 
+00308 extern uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd);
+00309 
+00311 extern uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd);
+00312 
+00314 extern uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd);
+00315 extern uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd);
+00316 extern uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd);
+00317 
+00320 extern uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep,
+00321                                      dwc_dma_t * addr, size_t buflen,
+00322                                      int flags);
+00323 
+00324 /******************************************************************************/
+00325 
+00328 #endif                          /* __DWC_PCD_IF_H__ */
+00329 
+00330 #endif                          /* DWC_HOST_ONLY */
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__if_8h.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__if_8h.html new file mode 100644 index 000000000000..0345b1668c8b --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__if_8h.html @@ -0,0 +1,976 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_pcd_if.h File Reference + + + + + + +

dwc_otg_pcd_if.h File Reference

This file defines DWC_OTG PCD Core API. More... +

+#include "dwc_os.h"
+#include "dwc_otg_core_if.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Structures

struct  dwc_otg_pcd_function_ops
 Function Driver Ops Data Structure. More...

Function Driver Callbacks

typedef int(*) dwc_completion_cb_t (dwc_otg_pcd_t *pcd, void *ep_handle, void *req_handle, int32_t status, uint32_t actual)
 This function will be called whenever a previously queued request has completed.
typedef int(*) dwc_isoc_completion_cb_t (dwc_otg_pcd_t *pcd, void *ep_handle, void *req_handle, int proc_buf_num)
 This function will be called whenever a previousle queued ISOC request has completed.
typedef int(*) dwc_setup_cb_t (dwc_otg_pcd_t *pcd, uint8_t *bytes)
 This function should handle any SETUP request that cannot be handled by the PCD Core.
typedef int(*) dwc_disconnect_cb_t (dwc_otg_pcd_t *pcd)
 This is called whenever the device has been disconnected.
+typedef int(*) dwc_connect_cb_t (dwc_otg_pcd_t *pcd, int speed)
 This function is called when device has been connected.
+typedef int(*) dwc_suspend_cb_t (dwc_otg_pcd_t *pcd)
 This function is called when device has been suspended.
typedef int(*) dwc_sleep_cb_t (dwc_otg_pcd_t *pcd)
 This function is called when device has received LPM tokens, i.e.
+typedef int(*) dwc_resume_cb_t (dwc_otg_pcd_t *pcd)
 This function is called when device has been resumed from suspend(L2) or L1 sleep state.
typedef int(*) dwc_hnp_params_changed_cb_t (dwc_otg_pcd_t *pcd)
 This function is called whenever hnp params has been changed.
+typedef int(*) dwc_reset_cb_t (dwc_otg_pcd_t *pcd)
 This function is called whenever USB RESET is detected.
+typedef int(*) cfi_setup_cb_t (dwc_otg_pcd_t *pcd, void *ctrl_req_bytes)

Function Driver Functions

dwc_otg_pcd_tdwc_otg_pcd_init (dwc_otg_core_if_t *core_if)
 Call this function to get pointer on dwc_otg_pcd_t, this pointer will be used for all PCD API functions.
void dwc_otg_pcd_remove (dwc_otg_pcd_t *pcd)
 Frees PCD allocated by dwc_otg_pcd_init.
void dwc_otg_pcd_start (dwc_otg_pcd_t *pcd, const struct dwc_otg_pcd_function_ops *fops)
 Call this to bind the function driver to the PCD Core.
int dwc_otg_pcd_ep_enable (dwc_otg_pcd_t *pcd, const uint8_t *ep_desc, void *ep_handle)
 Enables an endpoint for use.
int dwc_otg_pcd_ep_disable (dwc_otg_pcd_t *pcd, void *ep_handle)
 Disable the endpoint referenced by ep_handle.
int dwc_otg_pcd_ep_queue (dwc_otg_pcd_t *pcd, void *ep_handle, uint8_t *buf, dwc_dma_t dma_buf, uint32_t buflen, int zero, void *req_handle, int atomic_alloc)
 Queue a data transfer request on the endpoint referenced by ep_handle.
int dwc_otg_pcd_ep_dequeue (dwc_otg_pcd_t *pcd, void *ep_handle, void *req_handle)
 De-queue the specified data transfer that has not yet completed.
int dwc_otg_pcd_ep_halt (dwc_otg_pcd_t *pcd, void *ep_handle, int value)
 Halt (STALL) an endpoint or clear it.
int32_t dwc_otg_pcd_handle_intr (dwc_otg_pcd_t *pcd)
 This function should be called on every hardware interrupt.
+int dwc_otg_pcd_get_frame_number (dwc_otg_pcd_t *pcd)
 This function returns current frame number.
int dwc_otg_pcd_iso_ep_start (dwc_otg_pcd_t *pcd, void *ep_handle, uint8_t *buf0, uint8_t *buf1, dwc_dma_t dma0, dwc_dma_t dma1, int sync_frame, int dp_frame, int data_per_frame, int start_frame, int buf_proc_intrvl, void *req_handle, int atomic_alloc)
 Start isochronous transfers on the endpoint referenced by ep_handle.
int dwc_otg_pcd_iso_ep_stop (dwc_otg_pcd_t *pcd, void *ep_handle, void *req_handle)
 Stop ISOC transfers on endpoint referenced by ep_handle.
void dwc_otg_pcd_get_iso_packet_params (dwc_otg_pcd_t *pcd, void *ep_handle, void *iso_req_handle, int packet, int *status, int *actual, int *offset)
 Get ISOC packet status.
int dwc_otg_pcd_get_iso_packet_count (dwc_otg_pcd_t *pcd, void *ep_handle, void *iso_req_handle)
 Get ISOC packet count.
int dwc_otg_pcd_wakeup (dwc_otg_pcd_t *pcd)
 This function starts the SRP Protocol if no session is in progress.
+int dwc_otg_pcd_is_lpm_enabled (dwc_otg_pcd_t *pcd)
 This function returns 1 if LPM support is enabled, and 0 otherwise.
+int dwc_otg_pcd_get_rmwkup_enable (dwc_otg_pcd_t *pcd)
 This function returns 1 if remote wakeup is allowed and 0, otherwise.
+void dwc_otg_pcd_initiate_srp (dwc_otg_pcd_t *pcd)
 Initiate SRP.
+void dwc_otg_pcd_remote_wakeup (dwc_otg_pcd_t *pcd, int set)
 Starts remote wakeup signaling.
+uint32_t dwc_otg_pcd_is_dualspeed (dwc_otg_pcd_t *pcd)
 This function returns whether device is dualspeed.
+uint32_t dwc_otg_pcd_is_otg (dwc_otg_pcd_t *pcd)
 This function returns whether device is otg.
+uint32_t get_b_hnp_enable (dwc_otg_pcd_t *pcd)
 These functions allow to get hnp parameters.
+uint32_t get_a_hnp_support (dwc_otg_pcd_t *pcd)
+uint32_t get_a_alt_hnp_support (dwc_otg_pcd_t *pcd)
+uint8_t * cfiw_ep_alloc_buffer (dwc_otg_pcd_t *pcd, void *pep, dwc_dma_t *addr, size_t buflen, int flags)
 Allocate a cfi buffer.

Defines

+#define __DWC_PCD_IF_H__
+#define MAX_EP0_SIZE   64
 Maxpacket size for EP0.
+#define MAX_PACKET_SIZE   1024
 Maxpacket size for any EP.

Typedefs

+typedef dwc_otg_pcd dwc_otg_pcd_t
+


Detailed Description

+This file defines DWC_OTG PCD Core API. +

+ +

+Definition in file dwc_otg_pcd_if.h.


Typedef Documentation

+ +
+
+ + + + +
typedef int(*) dwc_completion_cb_t(dwc_otg_pcd_t *pcd, void *ep_handle, void *req_handle, int32_t status, uint32_t actual)
+
+
+ +

+This function will be called whenever a previously queued request has completed. +

+The status value will be set to -DWC_E_SHUTDOWN to indicated a failed or aborted transfer, or -DWC_E_RESTART to indicate the device was reset, or -DWC_E_TIMEOUT to indicate it timed out, or -DWC_E_INVALID to indicate invalid parameters. +

+Definition at line 61 of file dwc_otg_pcd_if.h. +

+

+ +

+
+ + + + +
typedef int(*) dwc_isoc_completion_cb_t(dwc_otg_pcd_t *pcd, void *ep_handle, void *req_handle, int proc_buf_num)
+
+
+ +

+This function will be called whenever a previousle queued ISOC request has completed. +

+Count of ISOC packets could be read using dwc_otg_pcd_get_iso_packet_count function. The status of each ISOC packet could be read using dwc_otg_pcd_get_iso_packet_* functions. +

+Definition at line 71 of file dwc_otg_pcd_if.h. +

+

+ +

+
+ + + + +
typedef int(*) dwc_setup_cb_t(dwc_otg_pcd_t *pcd, uint8_t *bytes)
+
+
+ +

+This function should handle any SETUP request that cannot be handled by the PCD Core. +

+This includes most GET_DESCRIPTORs, SET_CONFIGS, Any class-specific requests, etc. The function must non-blocking.

+Returns 0 on success. Returns -DWC_E_NOT_SUPPORTED if the request is not supported. Returns -DWC_E_INVALID if the setup request had invalid parameters or bytes. Returns -DWC_E_SHUTDOWN on any other error. +

+Definition at line 81 of file dwc_otg_pcd_if.h. +

+

+ +

+
+ + + + +
typedef int(*) dwc_disconnect_cb_t(dwc_otg_pcd_t *pcd)
+
+
+ +

+This is called whenever the device has been disconnected. +

+The function driver should take appropriate action to clean up all pending requests in the PCD Core, remove all endpoints (except ep0), and initialize back to reset state. +

+Definition at line 86 of file dwc_otg_pcd_if.h. +

+

+ +

+
+ + + + +
typedef int(*) dwc_sleep_cb_t(dwc_otg_pcd_t *pcd)
+
+
+ +

+This function is called when device has received LPM tokens, i.e. +

+device has been sent to sleep state. +

+Definition at line 93 of file dwc_otg_pcd_if.h. +

+

+ +

+
+ + + + +
typedef int(*) dwc_hnp_params_changed_cb_t(dwc_otg_pcd_t *pcd)
+
+
+ +

+This function is called whenever hnp params has been changed. +

+User can call get_b_hnp_enable, get_a_hnp_support, get_a_alt_hnp_support functions to get hnp parameters. +

+Definition at line 100 of file dwc_otg_pcd_if.h. +

+

+


Function Documentation

+ +
+
+ + + + + + + + + +
dwc_otg_pcd_t* dwc_otg_pcd_init (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+Call this function to get pointer on dwc_otg_pcd_t, this pointer will be used for all PCD API functions. +

+

Parameters:
+ + +
core_if The DWC_OTG Core
+
+ +

+Definition at line 1056 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_pcd_remove (dwc_otg_pcd_t pcd  ) 
+
+
+ +

+Frees PCD allocated by dwc_otg_pcd_init. +

+

Parameters:
+ + +
pcd The PCD
+
+ +

+Definition at line 1215 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void dwc_otg_pcd_start (dwc_otg_pcd_t pcd,
const struct dwc_otg_pcd_function_ops fops 
)
+
+
+ +

+Call this to bind the function driver to the PCD Core. +

+

Parameters:
+ + + +
pcd Pointer on dwc_otg_pcd_t returned by dwc_otg_pcd_init function.
fops The Function Driver Ops data structure containing pointers to all callbacks.
+
+ +

+Definition at line 117 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_pcd_ep_enable (dwc_otg_pcd_t pcd,
const uint8_t *  ep_desc,
void *  ep_handle 
)
+
+
+ +

+Enables an endpoint for use. +

+This function enables an endpoint in the PCD. The endpoint is described by the ep_desc which has the same format as a USB ep descriptor. The ep_handle parameter is used to refer to the endpoint from other API functions and in callbacks. Normally this should be called after a SET_CONFIGURATION/SET_INTERFACE to configure the core for that interface.

+Returns -DWC_E_INVALID if invalid parameters were passed. Returns -DWC_E_SHUTDOWN if any other error ocurred. Returns 0 on success.

+

Parameters:
+ + + + +
pcd The PCD
ep_desc Endpoint descriptor
ep_handle Handle on endpoint, that will be used to identify endpoint.
+
+ +

+Definition at line 1341 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
int dwc_otg_pcd_ep_disable (dwc_otg_pcd_t pcd,
void *  ep_handle 
)
+
+
+ +

+Disable the endpoint referenced by ep_handle. +

+Returns -DWC_E_INVALID if invalid parameters were passed. Returns -DWC_E_SHUTDOWN if any other error ocurred. Returns 0 on success. +

+Definition at line 1449 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_pcd_ep_queue (dwc_otg_pcd_t pcd,
void *  ep_handle,
uint8_t *  buf,
dwc_dma_t  dma_buf,
uint32_t  buflen,
int  zero,
void *  req_handle,
int  atomic_alloc 
)
+
+
+ +

+Queue a data transfer request on the endpoint referenced by ep_handle. +

+After the transfer is completes, the complete callback will be called with the request status.

+

Parameters:
+ + + + + + + + + +
pcd The PCD
ep_handle The handle of the endpoint
buf The buffer for the data
dma_buf The DMA buffer for the data
buflen The length of the data transfer
zero Specifies whether to send zero length last packet.
req_handle Set this handle to any value to use to reference this request in the ep_dequeue function or from the complete callback
atomic_alloc If driver need to perform atomic allocations for internal data structures.
+
+Returns -DWC_E_INVALID if invalid parameters were passed. Returns -DWC_E_SHUTDOWN if any other error ocurred. Returns 0 on success. +

+

Todo:
NGS Create a function for this.
+ +

+Definition at line 1502 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_pcd_ep_dequeue (dwc_otg_pcd_t pcd,
void *  ep_handle,
void *  req_handle 
)
+
+
+ +

+De-queue the specified data transfer that has not yet completed. +

+Returns -DWC_E_INVALID if invalid parameters were passed. Returns -DWC_E_SHUTDOWN if any other error ocurred. Returns 0 on success. +

+Definition at line 1694 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_pcd_ep_halt (dwc_otg_pcd_t pcd,
void *  ep_handle,
int  value 
)
+
+
+ +

+Halt (STALL) an endpoint or clear it. +

+Returns -DWC_E_INVALID if invalid parameters were passed. Returns -DWC_E_SHUTDOWN if any other error ocurred. Returns -DWC_E_AGAIN if the STALL cannot be sent and must be tried again later Returns 0 on success. +

+Definition at line 1733 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_pcd_handle_intr (dwc_otg_pcd_t pcd  ) 
+
+
+ +

+This function should be called on every hardware interrupt. +

+The PCD handles the device interrupts. Many conditions can cause a device interrupt. When an interrupt occurs, the device interrupt service routine determines the cause of the interrupt and dispatches handling to the appropriate function. These interrupt handling functions are described below.

+All interrupt registers are processed from LSB to MSB. +

+Definition at line 3971 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_pcd_iso_ep_start (dwc_otg_pcd_t pcd,
void *  ep_handle,
uint8_t *  buf0,
uint8_t *  buf1,
dwc_dma_t  dma0,
dwc_dma_t  dma1,
int  sync_frame,
int  dp_frame,
int  data_per_frame,
int  start_frame,
int  buf_proc_intrvl,
void *  req_handle,
int  atomic_alloc 
)
+
+
+ +

+Start isochronous transfers on the endpoint referenced by ep_handle. +

+For isochronous transfers duble buffering is used. After processing each of buffers comlete callback will be called with status for each transaction.

+

Parameters:
+ + + + + + + + + + + + + + +
pcd The PCD
ep_handle The handle of the endpoint
buf0 The virtual address of first data buffer
buf1 The virtual address of second data buffer
dma0 The DMA address of first data buffer
dma1 The DMA address of second data buffer
sync_frame Data pattern frame number
dp_frame Data size for pattern frame
data_per_frame Data size for regular frame
start_frame Frame number to start transfers, if -1 then start transfers ASAP.
buf_proc_intrvl Interval of ISOC Buffer processing
req_handle Handle of ISOC request
atomic_alloc Specefies whether to perform atomic allocation for internal data structures.
+
+Returns -DWC_E_NO_MEMORY if there is no enough memory. Returns -DWC_E_INVALID if incorrect arguments are passed to the function. Returns -DW_E_SHUTDOWN for any other error. Returns 0 on success +

+

Todo:
    +
  • pattern data support is to be implemented in the future
+
+ +

+Definition at line 685 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_pcd_iso_ep_stop (dwc_otg_pcd_t pcd,
void *  ep_handle,
void *  req_handle 
)
+
+
+ +

+Stop ISOC transfers on endpoint referenced by ep_handle. +

+

Parameters:
+ + + + +
pcd The PCD
ep_handle The handle of the endpoint
req_handle Handle of ISOC request
+
+Returns -DWC_E_INVALID if incorrect arguments are passed to the function Returns 0 on success +

+Definition at line 794 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void dwc_otg_pcd_get_iso_packet_params (dwc_otg_pcd_t pcd,
void *  ep_handle,
void *  iso_req_handle,
int  packet,
int *  status,
int *  actual,
int *  offset 
)
+
+
+ +

+Get ISOC packet status. +

+

Parameters:
+ + + + + + + + +
pcd The PCD
ep_handle The handle of the endpoint
iso_req_handle Isochronoush request handle
packet Number of packet
status Out parameter for returning status
actual Out parameter for returning actual length
offset Out parameter for returning offset
+
+ +

+Definition at line 862 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
int dwc_otg_pcd_get_iso_packet_count (dwc_otg_pcd_t pcd,
void *  ep_handle,
void *  iso_req_handle 
)
+
+
+ +

+Get ISOC packet count. +

+

Parameters:
+ + + + +
pcd The PCD
ep_handle The handle of the endpoint
iso_req_handle 
+
+ +

+Definition at line 850 of file dwc_otg_pcd.c. +

+

+ +

+
+ + + + + + + + + +
int dwc_otg_pcd_wakeup (dwc_otg_pcd_t pcd  ) 
+
+
+ +

+This function starts the SRP Protocol if no session is in progress. +

+If a session is already in progress, but the device is suspended, remote wakeup signaling is started. +

+Definition at line 1896 of file dwc_otg_pcd.c. +

+

+


Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__intr_8c-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__intr_8c-source.html new file mode 100644 index 000000000000..967087f4995d --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__intr_8c-source.html @@ -0,0 +1,3629 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_pcd_intr.c Source File + + + + + + +

dwc_otg_pcd_intr.c

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_intr.c $
+00003  * $Revision: #93 $
+00004  * $Date: 2009/04/02 $
+00005  * $Change: 1224216 $
+00006  *
+00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009  * otherwise expressly agreed to in writing between Synopsys and you.
+00010  *
+00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012  * any End User Software License Agreement or Agreement for Licensed Product
+00013  * with Synopsys or any supplement thereto. You are permitted to use and
+00014  * redistribute this Software in source and binary forms, with or without
+00015  * modification, provided that redistributions of source code must retain this
+00016  * notice. You may not view, use, disclose, copy or distribute this file or
+00017  * any information contained herein except pursuant to this license grant from
+00018  * Synopsys. If you do not agree with this notice, including the disclaimer
+00019  * below, then you are not authorized to use the Software.
+00020  *
+00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031  * DAMAGE.
+00032  * ========================================================================== */
+00033 #ifndef DWC_HOST_ONLY
+00034 
+00035 #include "dwc_otg_pcd.h"
+00036 
+00037 #ifdef DWC_UTE_CFI
+00038 #include "dwc_otg_cfi.h"
+00039 #endif
+00040 
+00041 //#define PRINT_CFI_DMA_DESCS
+00042 
+00043 #define DEBUG_EP0
+00044 
+00048 static void dwc_otg_pcd_update_otg(dwc_otg_pcd_t * pcd, const unsigned reset)
+00049 {
+00050 
+00051         if (reset) {
+00052                 pcd->b_hnp_enable = 0;
+00053                 pcd->a_hnp_support = 0;
+00054                 pcd->a_alt_hnp_support = 0;
+00055         }
+00056 
+00057         if (pcd->fops->hnp_changed) {
+00058                 pcd->fops->hnp_changed(pcd);
+00059         }
+00060 }
+00061 
+00076 static inline void print_ep0_state(dwc_otg_pcd_t * pcd)
+00077 {
+00078 #ifdef DEBUG
+00079         char str[40];
+00080 
+00081         switch (pcd->ep0state) {
+00082         case EP0_DISCONNECT:
+00083                 dwc_strcpy(str, "EP0_DISCONNECT");
+00084                 break;
+00085         case EP0_IDLE:
+00086                 dwc_strcpy(str, "EP0_IDLE");
+00087                 break;
+00088         case EP0_IN_DATA_PHASE:
+00089                 dwc_strcpy(str, "EP0_IN_DATA_PHASE");
+00090                 break;
+00091         case EP0_OUT_DATA_PHASE:
+00092                 dwc_strcpy(str, "EP0_OUT_DATA_PHASE");
+00093                 break;
+00094         case EP0_IN_STATUS_PHASE:
+00095                 dwc_strcpy(str, "EP0_IN_STATUS_PHASE");
+00096                 break;
+00097         case EP0_OUT_STATUS_PHASE:
+00098                 dwc_strcpy(str, "EP0_OUT_STATUS_PHASE");
+00099                 break;
+00100         case EP0_STALL:
+00101                 dwc_strcpy(str, "EP0_STALL");
+00102                 break;
+00103         default:
+00104                 dwc_strcpy(str, "EP0_INVALID");
+00105         }
+00106 
+00107         DWC_DEBUGPL(DBG_ANY, "%s(%d)\n", str, pcd->ep0state);
+00108 #endif
+00109 }
+00110 
+00111 #ifdef DWC_UTE_CFI
+00112 static inline void print_desc(struct dwc_otg_dma_desc *ddesc,
+00113                               const uint8_t * epname, int descnum)
+00114 {
+00115         CFI_INFO
+00116             ("%s DMA_DESC(%d) buf=0x%08x bytes=0x%04x; sp=0x%x; l=0x%x; sts=0x%02x; bs=0x%02x\n",
+00117              epname, descnum, ddesc->buf, ddesc->status.b.bytes,
+00118              ddesc->status.b.sp, ddesc->status.b.l, ddesc->status.b.sts,
+00119              ddesc->status.b.bs);
+00120 }
+00121 #endif
+00122 
+00126 static inline dwc_otg_pcd_ep_t *get_in_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num)
+00127 {
+00128         int i;
+00129         int num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps;
+00130         if (ep_num == 0) {
+00131                 return &pcd->ep0;
+00132         } else {
+00133                 for (i = 0; i < num_in_eps; ++i) {
+00134                         if (pcd->in_ep[i].dwc_ep.num == ep_num)
+00135                                 return &pcd->in_ep[i];
+00136                 }
+00137                 return 0;
+00138         }
+00139 }
+00140 
+00144 static inline dwc_otg_pcd_ep_t *get_out_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num)
+00145 {
+00146         int i;
+00147         int num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps;
+00148         if (ep_num == 0) {
+00149                 return &pcd->ep0;
+00150         } else {
+00151                 for (i = 0; i < num_out_eps; ++i) {
+00152                         if (pcd->out_ep[i].dwc_ep.num == ep_num)
+00153                                 return &pcd->out_ep[i];
+00154                 }
+00155                 return 0;
+00156         }
+00157 }
+00158 
+00163 dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex)
+00164 {
+00165         dwc_otg_pcd_ep_t *ep;
+00166         uint32_t ep_num = UE_GET_ADDR(wIndex);
+00167 
+00168         if (ep_num == 0) {
+00169                 ep = &pcd->ep0;
+00170         } else if (UE_GET_DIR(wIndex) == UE_DIR_IN) {   /* in ep */
+00171                 ep = &pcd->in_ep[ep_num - 1];
+00172         } else {
+00173                 ep = &pcd->out_ep[ep_num - 1];
+00174         }
+00175 
+00176         return ep;
+00177 }
+00178 
+00183 void start_next_request(dwc_otg_pcd_ep_t * ep)
+00184 {
+00185         dwc_otg_pcd_request_t *req = 0;
+00186         uint32_t max_transfer =
+00187             GET_CORE_IF(ep->pcd)->core_params->max_transfer_size;
+00188 
+00189 #ifdef DWC_UTE_CFI
+00190         struct dwc_otg_pcd *pcd;
+00191         pcd = ep->pcd;
+00192 #endif
+00193 
+00194         if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
+00195                 req = DWC_CIRCLEQ_FIRST(&ep->queue);
+00196 
+00197 #ifdef DWC_UTE_CFI
+00198                 if (ep->dwc_ep.buff_mode != BM_STANDARD) {
+00199                         ep->dwc_ep.cfi_req_len = req->length;
+00200                         pcd->cfi->ops.build_descriptors(pcd->cfi, pcd, ep, req);
+00201                 } else {
+00202 #endif
+00203                 /* Setup and start the Transfer */
+00204                 ep->dwc_ep.dma_addr = req->dma;
+00205                 ep->dwc_ep.start_xfer_buff = req->buf;
+00206                 ep->dwc_ep.xfer_buff = req->buf;
+00207                 ep->dwc_ep.sent_zlp = 0;
+00208                 ep->dwc_ep.total_len = req->length;
+00209                 ep->dwc_ep.xfer_len = 0;
+00210                 ep->dwc_ep.xfer_count = 0;
+00211 
+00212                 ep->dwc_ep.maxxfer = max_transfer;
+00213                 if (GET_CORE_IF(ep->pcd)->dma_desc_enable) {
+00214                         uint32_t out_max_xfer = DDMA_MAX_TRANSFER_SIZE
+00215                             - (DDMA_MAX_TRANSFER_SIZE % 4);
+00216                         if (ep->dwc_ep.is_in) {
+00217                                         if (ep->dwc_ep.maxxfer >
+00218                                             DDMA_MAX_TRANSFER_SIZE) {
+00219                                         ep->dwc_ep.maxxfer =
+00220                                             DDMA_MAX_TRANSFER_SIZE;
+00221                                 }
+00222                         } else {
+00223                                 if (ep->dwc_ep.maxxfer > out_max_xfer) {
+00224                                                 ep->dwc_ep.maxxfer =
+00225                                                     out_max_xfer;
+00226                                 }
+00227                         }
+00228                 }
+00229                 if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) {
+00230                         ep->dwc_ep.maxxfer -=
+00231                             (ep->dwc_ep.maxxfer % ep->dwc_ep.maxpacket);
+00232                 }
+00233                 if (req->sent_zlp) {
+00234                                 if ((ep->dwc_ep.total_len %
+00235                                      ep->dwc_ep.maxpacket == 0)
+00236                                     && (ep->dwc_ep.total_len != 0)) {
+00237                                 ep->dwc_ep.sent_zlp = 1;
+00238                         }
+00239 
+00240                 }
+00241 #ifdef DWC_UTE_CFI
+00242                 }
+00243 #endif
+00244                 dwc_otg_ep_start_transfer(GET_CORE_IF(ep->pcd), &ep->dwc_ep);
+00245         }
+00246 }
+00247 
+00252 int32_t dwc_otg_pcd_handle_sof_intr(dwc_otg_pcd_t * pcd)
+00253 {
+00254         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+00255 
+00256         gintsts_data_t gintsts;
+00257 
+00258         DWC_DEBUGPL(DBG_PCD, "SOF\n");
+00259 
+00260         /* Clear interrupt */
+00261         gintsts.d32 = 0;
+00262         gintsts.b.sofintr = 1;
+00263         dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
+00264 
+00265         return 1;
+00266 }
+00267 
+00285 int32_t dwc_otg_pcd_handle_rx_status_q_level_intr(dwc_otg_pcd_t * pcd)
+00286 {
+00287         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+00288         dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+00289         gintmsk_data_t gintmask = {.d32 = 0 };
+00290         device_grxsts_data_t status;
+00291         dwc_otg_pcd_ep_t *ep;
+00292         gintsts_data_t gintsts;
+00293 #ifdef DEBUG
+00294         static char *dpid_str[] = { "D0", "D2", "D1", "MDATA" };
+00295 #endif
+00296 
+00297         //DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _pcd);
+00298         /* Disable the Rx Status Queue Level interrupt */
+00299         gintmask.b.rxstsqlvl = 1;
+00300         dwc_modify_reg32(&global_regs->gintmsk, gintmask.d32, 0);
+00301 
+00302         /* Get the Status from the top of the FIFO */
+00303         status.d32 = dwc_read_reg32(&global_regs->grxstsp);
+00304 
+00305         DWC_DEBUGPL(DBG_PCD, "EP:%d BCnt:%d DPID:%s "
+00306                     "pktsts:%x Frame:%d(0x%0x)\n",
+00307                     status.b.epnum, status.b.bcnt,
+00308                     dpid_str[status.b.dpid],
+00309                     status.b.pktsts, status.b.fn, status.b.fn);
+00310         /* Get pointer to EP structure */
+00311         ep = get_out_ep(pcd, status.b.epnum);
+00312 
+00313         switch (status.b.pktsts) {
+00314         case DWC_DSTS_GOUT_NAK:
+00315                 DWC_DEBUGPL(DBG_PCDV, "Global OUT NAK\n");
+00316                 break;
+00317         case DWC_STS_DATA_UPDT:
+00318                 DWC_DEBUGPL(DBG_PCDV, "OUT Data Packet\n");
+00319                 if (status.b.bcnt && ep->dwc_ep.xfer_buff) {
+00321                         dwc_otg_read_packet(core_if,
+00322                                             ep->dwc_ep.xfer_buff,
+00323                                             status.b.bcnt);
+00324                         ep->dwc_ep.xfer_count += status.b.bcnt;
+00325                         ep->dwc_ep.xfer_buff += status.b.bcnt;
+00326                 }
+00327                 break;
+00328         case DWC_STS_XFER_COMP:
+00329                 DWC_DEBUGPL(DBG_PCDV, "OUT Complete\n");
+00330                 break;
+00331         case DWC_DSTS_SETUP_COMP:
+00332 #ifdef DEBUG_EP0
+00333                 DWC_DEBUGPL(DBG_PCDV, "Setup Complete\n");
+00334 #endif
+00335                 break;
+00336         case DWC_DSTS_SETUP_UPDT:
+00337                 dwc_otg_read_setup_packet(core_if, pcd->setup_pkt->d32);
+00338 #ifdef DEBUG_EP0
+00339                 DWC_DEBUGPL(DBG_PCD,
+00340                             "SETUP PKT: %02x.%02x v%04x i%04x l%04x\n",
+00341                             pcd->setup_pkt->req.bmRequestType,
+00342                             pcd->setup_pkt->req.bRequest,
+00343                             UGETW(pcd->setup_pkt->req.wValue),
+00344                             UGETW(pcd->setup_pkt->req.wIndex),
+00345                             UGETW(pcd->setup_pkt->req.wLength));
+00346 #endif
+00347                 ep->dwc_ep.xfer_count += status.b.bcnt;
+00348                 break;
+00349         default:
+00350                 DWC_DEBUGPL(DBG_PCDV, "Invalid Packet Status (0x%0x)\n",
+00351                             status.b.pktsts);
+00352                 break;
+00353         }
+00354 
+00355         /* Enable the Rx Status Queue Level interrupt */
+00356         dwc_modify_reg32(&global_regs->gintmsk, 0, gintmask.d32);
+00357         /* Clear interrupt */
+00358         gintsts.d32 = 0;
+00359         gintsts.b.rxstsqlvl = 1;
+00360         dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+00361 
+00362         //DWC_DEBUGPL(DBG_PCDV, "EXIT: %s\n", __func__);
+00363         return 1;
+00364 }
+00365 
+00378 static inline int get_ep_of_last_in_token(dwc_otg_core_if_t * core_if)
+00379 {
+00380         dwc_otg_device_global_regs_t *dev_global_regs =
+00381             core_if->dev_if->dev_global_regs;
+00382         const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth;
+00383         /* Number of Token Queue Registers */
+00384         const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8;
+00385         dtknq1_data_t dtknqr1;
+00386         uint32_t in_tkn_epnums[4];
+00387         int ndx = 0;
+00388         int i = 0;
+00389         volatile uint32_t *addr = &dev_global_regs->dtknqr1;
+00390         int epnum = 0;
+00391 
+00392         //DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH);
+00393 
+00394         /* Read the DTKNQ Registers */
+00395         for (i = 0; i < DTKNQ_REG_CNT; i++) {
+00396                 in_tkn_epnums[i] = dwc_read_reg32(addr);
+00397                 DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1,
+00398                             in_tkn_epnums[i]);
+00399                 if (addr == &dev_global_regs->dvbusdis) {
+00400                         addr = &dev_global_regs->dtknqr3_dthrctl;
+00401                 } else {
+00402                         ++addr;
+00403                 }
+00404 
+00405         }
+00406 
+00407         /* Copy the DTKNQR1 data to the bit field. */
+00408         dtknqr1.d32 = in_tkn_epnums[0];
+00409         /* Get the EP numbers */
+00410         in_tkn_epnums[0] = dtknqr1.b.epnums0_5;
+00411         ndx = dtknqr1.b.intknwptr - 1;
+00412 
+00413         //DWC_DEBUGPL(DBG_PCDV,"ndx=%d\n",ndx);
+00414         if (ndx == -1) {
+00417                 int cnt = TOKEN_Q_DEPTH;
+00418                 if (TOKEN_Q_DEPTH <= 6) {
+00419                         cnt = TOKEN_Q_DEPTH - 1;
+00420                 } else if (TOKEN_Q_DEPTH <= 14) {
+00421                         cnt = TOKEN_Q_DEPTH - 7;
+00422                 } else if (TOKEN_Q_DEPTH <= 22) {
+00423                         cnt = TOKEN_Q_DEPTH - 15;
+00424                 } else {
+00425                         cnt = TOKEN_Q_DEPTH - 23;
+00426                 }
+00427                 epnum = (in_tkn_epnums[DTKNQ_REG_CNT - 1] >> (cnt * 4)) & 0xF;
+00428         } else {
+00429                 if (ndx <= 5) {
+00430                         epnum = (in_tkn_epnums[0] >> (ndx * 4)) & 0xF;
+00431                 } else if (ndx <= 13) {
+00432                         ndx -= 6;
+00433                         epnum = (in_tkn_epnums[1] >> (ndx * 4)) & 0xF;
+00434                 } else if (ndx <= 21) {
+00435                         ndx -= 14;
+00436                         epnum = (in_tkn_epnums[2] >> (ndx * 4)) & 0xF;
+00437                 } else if (ndx <= 29) {
+00438                         ndx -= 22;
+00439                         epnum = (in_tkn_epnums[3] >> (ndx * 4)) & 0xF;
+00440                 }
+00441         }
+00442         //DWC_DEBUGPL(DBG_PCD,"epnum=%d\n",epnum);
+00443         return epnum;
+00444 }
+00445 
+00451 int32_t dwc_otg_pcd_handle_np_tx_fifo_empty_intr(dwc_otg_pcd_t * pcd)
+00452 {
+00453         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+00454         dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+00455         dwc_otg_dev_in_ep_regs_t *ep_regs;
+00456         gnptxsts_data_t txstatus = {.d32 = 0 };
+00457         gintsts_data_t gintsts;
+00458 
+00459         int epnum = 0;
+00460         dwc_otg_pcd_ep_t *ep = 0;
+00461         uint32_t len = 0;
+00462         int dwords;
+00463 
+00464         /* Get the epnum from the IN Token Learning Queue. */
+00465         epnum = get_ep_of_last_in_token(core_if);
+00466         ep = get_in_ep(pcd, epnum);
+00467 
+00468         DWC_DEBUGPL(DBG_PCD, "NP TxFifo Empty: %d \n", epnum);
+00469 
+00470         ep_regs = core_if->dev_if->in_ep_regs[epnum];
+00471 
+00472         len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
+00473         if (len > ep->dwc_ep.maxpacket) {
+00474                 len = ep->dwc_ep.maxpacket;
+00475         }
+00476         dwords = (len + 3) / 4;
+00477 
+00478         /* While there is space in the queue and space in the FIFO and
+00479          * More data to tranfer, Write packets to the Tx FIFO */
+00480         txstatus.d32 = dwc_read_reg32(&global_regs->gnptxsts);
+00481         DWC_DEBUGPL(DBG_PCDV, "b4 GNPTXSTS=0x%08x\n", txstatus.d32);
+00482 
+00483         while (txstatus.b.nptxqspcavail > 0 &&
+00484                txstatus.b.nptxfspcavail > dwords &&
+00485                ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len) {
+00486                 /* Write the FIFO */
+00487                 dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0);
+00488                 len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
+00489 
+00490                 if (len > ep->dwc_ep.maxpacket) {
+00491                         len = ep->dwc_ep.maxpacket;
+00492                 }
+00493 
+00494                 dwords = (len + 3) / 4;
+00495                 txstatus.d32 = dwc_read_reg32(&global_regs->gnptxsts);
+00496                 DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n", txstatus.d32);
+00497         }
+00498 
+00499         DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n",
+00500                     dwc_read_reg32(&global_regs->gnptxsts));
+00501 
+00502         /* Clear interrupt */
+00503         gintsts.d32 = 0;
+00504         gintsts.b.nptxfempty = 1;
+00505         dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+00506 
+00507         return 1;
+00508 }
+00509 
+00515 static int32_t write_empty_tx_fifo(dwc_otg_pcd_t * pcd, uint32_t epnum)
+00516 {
+00517         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+00518         dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+00519         dwc_otg_dev_in_ep_regs_t *ep_regs;
+00520         dtxfsts_data_t txstatus = {.d32 = 0 };
+00521         dwc_otg_pcd_ep_t *ep = 0;
+00522         uint32_t len = 0;
+00523         int dwords;
+00524 
+00525         ep = get_in_ep(pcd, epnum);
+00526 
+00527         DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum);
+00528 
+00529         ep_regs = core_if->dev_if->in_ep_regs[epnum];
+00530 
+00531         len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
+00532 
+00533         if (len > ep->dwc_ep.maxpacket) {
+00534                 len = ep->dwc_ep.maxpacket;
+00535         }
+00536 
+00537         dwords = (len + 3) / 4;
+00538 
+00539         /* While there is space in the queue and space in the FIFO and
+00540          * More data to tranfer, Write packets to the Tx FIFO */
+00541         txstatus.d32 = dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dtxfsts);
+00542         DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32);
+00543 
+00544         while (txstatus.b.txfspcavail > dwords &&
+00545                ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len &&
+00546                ep->dwc_ep.xfer_len != 0) {
+00547                 /* Write the FIFO */
+00548                 dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0);
+00549 
+00550                 len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count;
+00551                 if (len > ep->dwc_ep.maxpacket) {
+00552                         len = ep->dwc_ep.maxpacket;
+00553                 }
+00554 
+00555                 dwords = (len + 3) / 4;
+00556                 txstatus.d32 =
+00557                     dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dtxfsts);
+00558                 DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum,
+00559                             txstatus.d32);
+00560         }
+00561 
+00562         DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum,
+00563                     dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dtxfsts));
+00564 
+00565         return 1;
+00566 }
+00567 
+00573 void dwc_otg_pcd_stop(dwc_otg_pcd_t * pcd)
+00574 {
+00575         int i, num_in_eps, num_out_eps;
+00576         dwc_otg_pcd_ep_t *ep;
+00577 
+00578         gintmsk_data_t intr_mask = {.d32 = 0 };
+00579 
+00580         DWC_SPINLOCK(pcd->lock);
+00581 
+00582         num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps;
+00583         num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps;
+00584 
+00585         DWC_DEBUGPL(DBG_PCDV, "%s() \n", __func__);
+00586         /* don't disconnect drivers more than once */
+00587         if (pcd->ep0state == EP0_DISCONNECT) {
+00588                 DWC_DEBUGPL(DBG_ANY, "%s() Already Disconnected\n", __func__);
+00589                 return;
+00590         }
+00591         pcd->ep0state = EP0_DISCONNECT;
+00592 
+00593         /* Reset the OTG state. */
+00594         dwc_otg_pcd_update_otg(pcd, 1);
+00595 
+00596         /* Disable the NP Tx Fifo Empty Interrupt. */
+00597         intr_mask.b.nptxfempty = 1;
+00598         dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
+00599                          intr_mask.d32, 0);
+00600 
+00601         /* Flush the FIFOs */
+00603         dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd), 0x10);
+00604         dwc_otg_flush_rx_fifo(GET_CORE_IF(pcd));
+00605 
+00606         /* prevent new request submissions, kill any outstanding requests  */
+00607         ep = &pcd->ep0;
+00608         dwc_otg_request_nuke(ep);
+00609         /* prevent new request submissions, kill any outstanding requests  */
+00610         for (i = 0; i < num_in_eps; i++) {
+00611                 dwc_otg_pcd_ep_t *ep = &pcd->in_ep[i];
+00612                 dwc_otg_request_nuke(ep);
+00613         }
+00614         /* prevent new request submissions, kill any outstanding requests  */
+00615         for (i = 0; i < num_out_eps; i++) {
+00616                 dwc_otg_pcd_ep_t *ep = &pcd->out_ep[i];
+00617                 dwc_otg_request_nuke(ep);
+00618         }
+00619 
+00620         /* report disconnect; the driver is already quiesced */
+00621         if (pcd->fops->disconnect) {
+00622                 DWC_SPINUNLOCK(pcd->lock);
+00623                 pcd->fops->disconnect(pcd);
+00624                 DWC_SPINLOCK(pcd->lock);
+00625         }
+00626         DWC_SPINUNLOCK(pcd->lock);
+00627 }
+00628 
+00632 int32_t dwc_otg_pcd_handle_i2c_intr(dwc_otg_pcd_t * pcd)
+00633 {
+00634         gintmsk_data_t intr_mask = {.d32 = 0 };
+00635         gintsts_data_t gintsts;
+00636 
+00637         DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "i2cintr");
+00638         intr_mask.b.i2cintr = 1;
+00639         dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
+00640                          intr_mask.d32, 0);
+00641 
+00642         /* Clear interrupt */
+00643         gintsts.d32 = 0;
+00644         gintsts.b.i2cintr = 1;
+00645         dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
+00646                         gintsts.d32);
+00647         return 1;
+00648 }
+00649 
+00653 int32_t dwc_otg_pcd_handle_early_suspend_intr(dwc_otg_pcd_t * pcd)
+00654 {
+00655         gintsts_data_t gintsts;
+00656 #if defined(VERBOSE)
+00657         DWC_PRINTF("Early Suspend Detected\n");
+00658 #endif
+00659         /* Clear interrupt */
+00660         gintsts.d32 = 0;
+00661         gintsts.b.erlysuspend = 1;
+00662         dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
+00663                         gintsts.d32);
+00664         return 1;
+00665 }
+00666 
+00684 static inline void ep0_out_start(dwc_otg_core_if_t * core_if,
+00685                                  dwc_otg_pcd_t * pcd)
+00686 {
+00687         dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+00688         deptsiz0_data_t doeptsize0 = {.d32 = 0 };
+00689         dwc_otg_dev_dma_desc_t *dma_desc;
+00690         depctl_data_t doepctl = {.d32 = 0 };
+00691 
+00692 #ifdef VERBOSE
+00693         DWC_DEBUGPL(DBG_PCDV, "%s() doepctl0=%0x\n", __func__,
+00694                     dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl));
+00695 #endif
+00696 
+00697         doeptsize0.b.supcnt = 3;
+00698         doeptsize0.b.pktcnt = 1;
+00699         doeptsize0.b.xfersize = 8 * 3;
+00700 
+00701         if (core_if->dma_enable) {
+00702                 if (!core_if->dma_desc_enable) {
+00704                         dwc_write_reg32(&dev_if->out_ep_regs[0]->doeptsiz,
+00705                                         doeptsize0.d32);
+00706 
+00708                         dwc_write_reg32(&dev_if->out_ep_regs[0]->doepdma,
+00709                                         pcd->setup_pkt_dma_handle);
+00710                 } else {
+00711                         dev_if->setup_desc_index =
+00712                             (dev_if->setup_desc_index + 1) & 1;
+00713                         dma_desc =
+00714                             dev_if->setup_desc_addr[dev_if->setup_desc_index];
+00715 
+00717                         dma_desc->status.b.bs = BS_HOST_BUSY;
+00718                         dma_desc->status.b.l = 1;
+00719                         dma_desc->status.b.ioc = 1;
+00720                         dma_desc->status.b.bytes = pcd->ep0.dwc_ep.maxpacket;
+00721                         dma_desc->buf = pcd->setup_pkt_dma_handle;
+00722                         dma_desc->status.b.bs = BS_HOST_READY;
+00723 
+00725                         dwc_write_reg32(&dev_if->out_ep_regs[0]->doepdma,
+00726                                         dev_if->dma_setup_desc_addr[dev_if->
+00727                                                                     setup_desc_index]);
+00728                 }
+00729 
+00730         } else {
+00732                 dwc_write_reg32(&dev_if->out_ep_regs[0]->doeptsiz,
+00733                                 doeptsize0.d32);
+00734         }
+00735 
+00737         doepctl.b.epena = 1;
+00738         doepctl.b.cnak = 1;
+00739         dwc_write_reg32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
+00740 
+00741 #ifdef VERBOSE
+00742         DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
+00743                     dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl));
+00744         DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
+00745                     dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl));
+00746 #endif
+00747 }
+00748 
+00772 int32_t dwc_otg_pcd_handle_usb_reset_intr(dwc_otg_pcd_t * pcd)
+00773 {
+00774         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+00775         dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+00776         depctl_data_t doepctl = {.d32 = 0 };
+00777         daint_data_t daintmsk = {.d32 = 0 };
+00778         doepmsk_data_t doepmsk = {.d32 = 0 };
+00779         diepmsk_data_t diepmsk = {.d32 = 0 };
+00780         dcfg_data_t dcfg = {.d32 = 0 };
+00781         grstctl_t resetctl = {.d32 = 0 };
+00782         dctl_data_t dctl = {.d32 = 0 };
+00783         int i = 0;
+00784         gintsts_data_t gintsts;
+00785         pcgcctl_data_t power = {.d32 = 0 };
+00786 
+00787         power.d32 = dwc_read_reg32(core_if->pcgcctl);
+00788         if (power.b.stoppclk) {
+00789                 power.d32 = 0;
+00790                 power.b.stoppclk = 1;
+00791                 dwc_modify_reg32(core_if->pcgcctl, power.d32, 0);
+00792 
+00793                 power.b.pwrclmp = 1;
+00794                 dwc_modify_reg32(core_if->pcgcctl, power.d32, 0);
+00795 
+00796                 power.b.rstpdwnmodule = 1;
+00797                 dwc_modify_reg32(core_if->pcgcctl, power.d32, 0);
+00798         }
+00799 
+00800         core_if->lx_state = DWC_OTG_L0;
+00801 
+00802         DWC_PRINTF("USB RESET\n");
+00803 #ifdef DWC_EN_ISOC
+00804         for (i = 1; i < 16; ++i) {
+00805                 dwc_otg_pcd_ep_t *ep;
+00806                 dwc_ep_t *dwc_ep;
+00807                 ep = get_in_ep(pcd, i);
+00808                 if (ep != 0) {
+00809                         dwc_ep = &ep->dwc_ep;
+00810                         dwc_ep->next_frame = 0xffffffff;
+00811                 }
+00812         }
+00813 #endif                          /* DWC_EN_ISOC */
+00814 
+00815         /* reset the HNP settings */
+00816         dwc_otg_pcd_update_otg(pcd, 1);
+00817 
+00818         /* Clear the Remote Wakeup Signalling */
+00819         dctl.b.rmtwkupsig = 1;
+00820         dwc_modify_reg32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0);
+00821 
+00822         /* Set NAK for all OUT EPs */
+00823         doepctl.b.snak = 1;
+00824         for (i = 0; i <= dev_if->num_out_eps; i++) {
+00825                 dwc_write_reg32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32);
+00826         }
+00827 
+00828         /* Flush the NP Tx FIFO */
+00829         dwc_otg_flush_tx_fifo(core_if, 0x10);
+00830         /* Flush the Learning Queue */
+00831         resetctl.b.intknqflsh = 1;
+00832         dwc_write_reg32(&core_if->core_global_regs->grstctl, resetctl.d32);
+00833 
+00834         if (core_if->multiproc_int_enable) {
+00835                 daintmsk.b.inep0 = 1;
+00836                 daintmsk.b.outep0 = 1;
+00837                 dwc_write_reg32(&dev_if->dev_global_regs->deachintmsk,
+00838                                 daintmsk.d32);
+00839 
+00840                 doepmsk.b.setup = 1;
+00841                 doepmsk.b.xfercompl = 1;
+00842                 doepmsk.b.ahberr = 1;
+00843                 doepmsk.b.epdisabled = 1;
+00844 
+00845                 if (core_if->dma_desc_enable) {
+00846                         doepmsk.b.stsphsercvd = 1;
+00847                         doepmsk.b.bna = 1;
+00848                 }
+00849 /*              
+00850                 doepmsk.b.babble = 1;
+00851                 doepmsk.b.nyet = 1;
+00852                 
+00853                 if(core_if->dma_enable) {
+00854                         doepmsk.b.nak = 1;
+00855                 }
+00856 */
+00857                 dwc_write_reg32(&dev_if->dev_global_regs->doepeachintmsk[0],
+00858                                 doepmsk.d32);
+00859 
+00860                 diepmsk.b.xfercompl = 1;
+00861                 diepmsk.b.timeout = 1;
+00862                 diepmsk.b.epdisabled = 1;
+00863                 diepmsk.b.ahberr = 1;
+00864                 diepmsk.b.intknepmis = 1;
+00865 
+00866                 if (core_if->dma_desc_enable) {
+00867                         diepmsk.b.bna = 1;
+00868                 }
+00869 /*              
+00870                 if(core_if->dma_enable) {
+00871                         diepmsk.b.nak = 1;
+00872                 }
+00873 */
+00874                 dwc_write_reg32(&dev_if->dev_global_regs->diepeachintmsk[0],
+00875                                 diepmsk.d32);
+00876         } else {
+00877                 daintmsk.b.inep0 = 1;
+00878                 daintmsk.b.outep0 = 1;
+00879                 dwc_write_reg32(&dev_if->dev_global_regs->daintmsk,
+00880                                 daintmsk.d32);
+00881 
+00882                 doepmsk.b.setup = 1;
+00883                 doepmsk.b.xfercompl = 1;
+00884                 doepmsk.b.ahberr = 1;
+00885                 doepmsk.b.epdisabled = 1;
+00886 
+00887                 if (core_if->dma_desc_enable) {
+00888                         doepmsk.b.stsphsercvd = 1;
+00889                         doepmsk.b.bna = 1;
+00890                 }
+00891                 dwc_write_reg32(&dev_if->dev_global_regs->doepmsk, doepmsk.d32);
+00892 
+00893                 diepmsk.b.xfercompl = 1;
+00894                 diepmsk.b.timeout = 1;
+00895                 diepmsk.b.epdisabled = 1;
+00896                 diepmsk.b.ahberr = 1;
+00897                 diepmsk.b.intknepmis = 1;
+00898 
+00899                 if (core_if->dma_desc_enable) {
+00900                         diepmsk.b.bna = 1;
+00901                 }
+00902 
+00903                 dwc_write_reg32(&dev_if->dev_global_regs->diepmsk, diepmsk.d32);
+00904         }
+00905 
+00906         /* Reset Device Address */
+00907         dcfg.d32 = dwc_read_reg32(&dev_if->dev_global_regs->dcfg);
+00908         dcfg.b.devaddr = 0;
+00909         dwc_write_reg32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
+00910 
+00911         /* setup EP0 to receive SETUP packets */
+00912         ep0_out_start(core_if, pcd);
+00913 
+00914         /* Clear interrupt */
+00915         gintsts.d32 = 0;
+00916         gintsts.b.usbreset = 1;
+00917         dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
+00918 
+00919         return 1;
+00920 }
+00921 
+00928 static int get_device_speed(dwc_otg_core_if_t * core_if)
+00929 {
+00930         dsts_data_t dsts;
+00931         int speed = 0;
+00932         dsts.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
+00933 
+00934         switch (dsts.b.enumspd) {
+00935         case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
+00936                 speed = USB_SPEED_HIGH;
+00937                 break;
+00938         case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
+00939         case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
+00940                 speed = USB_SPEED_FULL;
+00941                 break;
+00942 
+00943         case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
+00944                 speed = USB_SPEED_LOW;
+00945                 break;
+00946         }
+00947 
+00948         return speed;
+00949 }
+00950 
+00956 int32_t dwc_otg_pcd_handle_enum_done_intr(dwc_otg_pcd_t * pcd)
+00957 {
+00958         dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
+00959         gintsts_data_t gintsts;
+00960         gusbcfg_data_t gusbcfg;
+00961         dwc_otg_core_global_regs_t *global_regs =
+00962             GET_CORE_IF(pcd)->core_global_regs;
+00963         uint8_t utmi16b, utmi8b;
+00964         int speed;
+00965         DWC_DEBUGPL(DBG_PCD, "SPEED ENUM\n");
+00966 
+00967         if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_2_60a) {
+00968                 utmi16b = 6;
+00969                 utmi8b = 9;
+00970         } else {
+00971                 utmi16b = 4;
+00972                 utmi8b = 8;
+00973         }
+00974         dwc_otg_ep0_activate(GET_CORE_IF(pcd), &ep0->dwc_ep);
+00975 
+00976 #ifdef DEBUG_EP0
+00977         print_ep0_state(pcd);
+00978 #endif
+00979 
+00980         if (pcd->ep0state == EP0_DISCONNECT) {
+00981                 pcd->ep0state = EP0_IDLE;
+00982         } else if (pcd->ep0state == EP0_STALL) {
+00983                 pcd->ep0state = EP0_IDLE;
+00984         }
+00985 
+00986         pcd->ep0state = EP0_IDLE;
+00987 
+00988         ep0->stopped = 0;
+00989 
+00990         speed = get_device_speed(GET_CORE_IF(pcd));
+00991         pcd->fops->connect(pcd, speed);
+00992 
+00993         /* Set USB turnaround time based on device speed and PHY interface. */
+00994         gusbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
+00995         if (speed == USB_SPEED_HIGH) {
+00996                 if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
+00997                     DWC_HWCFG2_HS_PHY_TYPE_ULPI) {
+00998                         /* ULPI interface */
+00999                         gusbcfg.b.usbtrdtim = 9;
+01000                 }
+01001                 if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
+01002                     DWC_HWCFG2_HS_PHY_TYPE_UTMI) {
+01003                         /* UTMI+ interface */
+01004                         if (GET_CORE_IF(pcd)->hwcfg4.b.utmi_phy_data_width == 0) {
+01005                                 gusbcfg.b.usbtrdtim = utmi8b;
+01006                         } else if (GET_CORE_IF(pcd)->hwcfg4.b.
+01007                                    utmi_phy_data_width == 1) {
+01008                                 gusbcfg.b.usbtrdtim = utmi16b;
+01009                         } else if (GET_CORE_IF(pcd)->core_params->
+01010                                    phy_utmi_width == 8) {
+01011                                 gusbcfg.b.usbtrdtim = utmi8b;
+01012                         } else {
+01013                                 gusbcfg.b.usbtrdtim = utmi16b;
+01014                         }
+01015                 }
+01016                 if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type ==
+01017                     DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI) {
+01018                         /* UTMI+  OR  ULPI interface */
+01019                         if (gusbcfg.b.ulpi_utmi_sel == 1) {
+01020                                 /* ULPI interface */
+01021                                 gusbcfg.b.usbtrdtim = 9;
+01022                         } else {
+01023                                 /* UTMI+ interface */
+01024                                 if (GET_CORE_IF(pcd)->core_params->
+01025                                     phy_utmi_width == 16) {
+01026                                         gusbcfg.b.usbtrdtim = utmi16b;
+01027                                 } else {
+01028                                         gusbcfg.b.usbtrdtim = utmi8b;
+01029                                 }
+01030                         }
+01031                 }
+01032         } else {
+01033                 /* Full or low speed */
+01034                 gusbcfg.b.usbtrdtim = 9;
+01035         }
+01036         dwc_write_reg32(&global_regs->gusbcfg, gusbcfg.d32);
+01037 
+01038         /* Clear interrupt */
+01039         gintsts.d32 = 0;
+01040         gintsts.b.enumdone = 1;
+01041         dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
+01042                         gintsts.d32);
+01043         return 1;
+01044 }
+01045 
+01051 int32_t dwc_otg_pcd_handle_isoc_out_packet_dropped_intr(dwc_otg_pcd_t * pcd)
+01052 {
+01053         gintmsk_data_t intr_mask = {.d32 = 0 };
+01054         gintsts_data_t gintsts;
+01055 
+01056         DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
+01057                    "ISOC Out Dropped");
+01058 
+01059         intr_mask.b.isooutdrop = 1;
+01060         dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
+01061                          intr_mask.d32, 0);
+01062 
+01063         /* Clear interrupt */
+01064         gintsts.d32 = 0;
+01065         gintsts.b.isooutdrop = 1;
+01066         dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
+01067                         gintsts.d32);
+01068 
+01069         return 1;
+01070 }
+01071 
+01077 int32_t dwc_otg_pcd_handle_end_periodic_frame_intr(dwc_otg_pcd_t * pcd)
+01078 {
+01079         gintmsk_data_t intr_mask = {.d32 = 0 };
+01080         gintsts_data_t gintsts;
+01081         DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "EOP");
+01082 
+01083         intr_mask.b.eopframe = 1;
+01084         dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
+01085                          intr_mask.d32, 0);
+01086 
+01087         /* Clear interrupt */
+01088         gintsts.d32 = 0;
+01089         gintsts.b.eopframe = 1;
+01090         dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
+01091                         gintsts.d32);
+01092 
+01093         return 1;
+01094 }
+01095 
+01105 int32_t dwc_otg_pcd_handle_ep_mismatch_intr(dwc_otg_core_if_t * core_if)
+01106 {
+01107         gintsts_data_t gintsts;
+01108         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if);
+01109 
+01110         /* Clear interrupt */
+01111         gintsts.d32 = 0;
+01112         gintsts.b.epmismatch = 1;
+01113         dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
+01114 
+01115         return 1;
+01116 }
+01117 
+01121 static inline void ep0_do_stall(dwc_otg_pcd_t * pcd, const int err_val)
+01122 {
+01123         dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
+01124         usb_device_request_t *ctrl = &pcd->setup_pkt->req;
+01125         DWC_WARN("req %02x.%02x protocol STALL; err %d\n",
+01126                  ctrl->bmRequestType, ctrl->bRequest, err_val);
+01127 
+01128         ep0->dwc_ep.is_in = 1;
+01129         dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep0->dwc_ep);
+01130         pcd->ep0.stopped = 1;
+01131         pcd->ep0state = EP0_IDLE;
+01132         ep0_out_start(GET_CORE_IF(pcd), pcd);
+01133 }
+01134 
+01138 static inline void do_gadget_setup(dwc_otg_pcd_t * pcd,
+01139                                    usb_device_request_t * ctrl)
+01140 {
+01141         int ret = 0;
+01142         DWC_SPINUNLOCK(pcd->lock);
+01143         ret = pcd->fops->setup(pcd, (uint8_t *) ctrl);
+01144         DWC_SPINLOCK(pcd->lock);
+01145         if (ret < 0) {
+01146                 ep0_do_stall(pcd, ret);
+01147         }
+01148 
+01161         if (ret == 256 + 999) {
+01162                 pcd->request_config = 1;
+01163         }
+01164 }
+01165 
+01166 #ifdef DWC_UTE_CFI
+01167 
+01171 static inline int cfi_gadget_setup(dwc_otg_pcd_t * pcd,
+01172                                    struct cfi_usb_ctrlrequest *ctrl_req)
+01173 {
+01174         int ret = 0;
+01175 
+01176         if (pcd->fops && pcd->fops->cfi_setup) {
+01177                 DWC_SPINUNLOCK(pcd->lock);
+01178                 ret = pcd->fops->cfi_setup(pcd, ctrl_req);
+01179                 DWC_SPINLOCK(pcd->lock);
+01180                 if (ret < 0) {
+01181                         ep0_do_stall(pcd, ret);
+01182                         return ret;
+01183                 }
+01184         }
+01185 
+01186         return ret;
+01187 }
+01188 #endif
+01189 
+01194 static inline void do_setup_in_status_phase(dwc_otg_pcd_t * pcd)
+01195 {
+01196         dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
+01197         if (pcd->ep0state == EP0_STALL) {
+01198                 return;
+01199         }
+01200 
+01201         pcd->ep0state = EP0_IN_STATUS_PHASE;
+01202 
+01203         /* Prepare for more SETUP Packets */
+01204         DWC_DEBUGPL(DBG_PCD, "EP0 IN ZLP\n");
+01205         ep0->dwc_ep.xfer_len = 0;
+01206         ep0->dwc_ep.xfer_count = 0;
+01207         ep0->dwc_ep.is_in = 1;
+01208         ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle;
+01209         dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
+01210 
+01211         /* Prepare for more SETUP Packets */
+01212         //ep0_out_start(GET_CORE_IF(pcd), pcd);
+01213 }
+01214 
+01219 static inline void do_setup_out_status_phase(dwc_otg_pcd_t * pcd)
+01220 {
+01221         dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
+01222         if (pcd->ep0state == EP0_STALL) {
+01223                 DWC_DEBUGPL(DBG_PCD, "EP0 STALLED\n");
+01224                 return;
+01225         }
+01226         pcd->ep0state = EP0_OUT_STATUS_PHASE;
+01227 
+01228         DWC_DEBUGPL(DBG_PCD, "EP0 OUT ZLP\n");
+01229         ep0->dwc_ep.xfer_len = 0;
+01230         ep0->dwc_ep.xfer_count = 0;
+01231         ep0->dwc_ep.is_in = 0;
+01232         ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle;
+01233         dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
+01234 
+01235         /* Prepare for more SETUP Packets */
+01236         if (GET_CORE_IF(pcd)->dma_enable == 0) {
+01237                 ep0_out_start(GET_CORE_IF(pcd), pcd);
+01238         }
+01239 }
+01240 
+01245 static inline void pcd_clear_halt(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep)
+01246 {
+01247         if (ep->dwc_ep.stall_clear_flag == 0)
+01248                 dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep);
+01249 
+01250         /* Reactive the EP */
+01251         dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep);
+01252         if (ep->stopped) {
+01253                 ep->stopped = 0;
+01254                 /* If there is a request in the EP queue start it */
+01255 
+01259                 /*
+01260                  * Above fixme is solved by implmenting a tasklet to call the
+01261                  * start_next_request(), outside of interrupt context at some
+01262                  * time after the current time, after a clear-halt setup packet.
+01263                  * Still need to implement ep mismatch in the future if a gadget
+01264                  * ever uses more than one endpoint at once
+01265                  */
+01266                 ep->queue_sof = 1;
+01267                 DWC_TASK_SCHEDULE(pcd->start_xfer_tasklet);
+01268         }
+01269         /* Start Control Status Phase */
+01270         do_setup_in_status_phase(pcd);
+01271 }
+01272 
+01284 void do_test_mode(void *data)
+01285 {
+01286         dctl_data_t dctl;
+01287         dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data;
+01288         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+01289         int test_mode = pcd->test_mode;
+01290 
+01291 //        DWC_WARN("%s() has not been tested since being rewritten!\n", __func__);
+01292 
+01293         dctl.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dctl);
+01294         switch (test_mode) {
+01295         case 1:         // TEST_J
+01296                 dctl.b.tstctl = 1;
+01297                 break;
+01298 
+01299         case 2:         // TEST_K
+01300                 dctl.b.tstctl = 2;
+01301                 break;
+01302 
+01303         case 3:         // TEST_SE0_NAK
+01304                 dctl.b.tstctl = 3;
+01305                 break;
+01306 
+01307         case 4:         // TEST_PACKET
+01308                 dctl.b.tstctl = 4;
+01309                 break;
+01310 
+01311         case 5:         // TEST_FORCE_ENABLE
+01312                 dctl.b.tstctl = 5;
+01313                 break;
+01314         }
+01315         dwc_write_reg32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32);
+01316 }
+01317 
+01321 static inline void do_get_status(dwc_otg_pcd_t * pcd)
+01322 {
+01323         usb_device_request_t ctrl = pcd->setup_pkt->req;
+01324         dwc_otg_pcd_ep_t *ep;
+01325         dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
+01326         uint16_t *status = pcd->status_buf;
+01327 
+01328 #ifdef DEBUG_EP0
+01329         DWC_DEBUGPL(DBG_PCD,
+01330                     "GET_STATUS %02x.%02x v%04x i%04x l%04x\n",
+01331                     ctrl.bmRequestType, ctrl.bRequest,
+01332                     UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
+01333                     UGETW(ctrl.wLength));
+01334 #endif
+01335 
+01336         switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
+01337         case UT_DEVICE:
+01338                 *status = 0x1;  /* Self powered */
+01339                 *status |= pcd->remote_wakeup_enable << 1;
+01340                 break;
+01341 
+01342         case UT_INTERFACE:
+01343                 *status = 0;
+01344                 break;
+01345 
+01346         case UT_ENDPOINT:
+01347                 ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
+01348                 if (ep == 0 || UGETW(ctrl.wLength) > 2) {
+01349                         ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
+01350                         return;
+01351                 }
+01353                 *status = ep->stopped;
+01354                 break;
+01355         }
+01356         pcd->ep0_pending = 1;
+01357         ep0->dwc_ep.start_xfer_buff = (uint8_t *) status;
+01358         ep0->dwc_ep.xfer_buff = (uint8_t *) status;
+01359         ep0->dwc_ep.dma_addr = pcd->status_buf_dma_handle;
+01360         ep0->dwc_ep.xfer_len = 2;
+01361         ep0->dwc_ep.xfer_count = 0;
+01362         ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len;
+01363         dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep);
+01364 }
+01365 
+01369 static inline void do_set_feature(dwc_otg_pcd_t * pcd)
+01370 {
+01371         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+01372         dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+01373         usb_device_request_t ctrl = pcd->setup_pkt->req;
+01374         dwc_otg_pcd_ep_t *ep = 0;
+01375         int32_t otg_cap_param = core_if->core_params->otg_cap;
+01376         gotgctl_data_t gotgctl = {.d32 = 0 };
+01377 
+01378         DWC_DEBUGPL(DBG_PCD, "SET_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
+01379                     ctrl.bmRequestType, ctrl.bRequest,
+01380                     UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
+01381                     UGETW(ctrl.wLength));
+01382         DWC_DEBUGPL(DBG_PCD, "otg_cap=%d\n", otg_cap_param);
+01383 
+01384         switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
+01385         case UT_DEVICE:
+01386                 switch (UGETW(ctrl.wValue)) {
+01387                 case UF_DEVICE_REMOTE_WAKEUP:
+01388                         pcd->remote_wakeup_enable = 1;
+01389                         break;
+01390 
+01391                 case UF_TEST_MODE:
+01392                         /* Setup the Test Mode tasklet to do the Test
+01393                          * Packet generation after the SETUP Status
+01394                          * phase has completed. */
+01395 
+01399                         pcd->test_mode = UGETW(ctrl.wIndex) >> 8;
+01400                         DWC_TASK_SCHEDULE(pcd->test_mode_tasklet);
+01401                         break;
+01402 
+01403                 case UF_DEVICE_B_HNP_ENABLE:
+01404                         DWC_DEBUGPL(DBG_PCDV,
+01405                                     "SET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n");
+01406 
+01407                         /* dev may initiate HNP */
+01408                         if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
+01409                                 pcd->b_hnp_enable = 1;
+01410                                 dwc_otg_pcd_update_otg(pcd, 0);
+01411                                 DWC_DEBUGPL(DBG_PCD, "Request B HNP\n");
+01414                                 gotgctl.b.devhnpen = 1;
+01415                                 gotgctl.b.hnpreq = 1;
+01416                                 dwc_write_reg32(&global_regs->gotgctl,
+01417                                                 gotgctl.d32);
+01418                         } else {
+01419                                 ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
+01420                         }
+01421                         break;
+01422 
+01423                 case UF_DEVICE_A_HNP_SUPPORT:
+01424                         /* RH port supports HNP */
+01425                         DWC_DEBUGPL(DBG_PCDV,
+01426                                     "SET_FEATURE: USB_DEVICE_A_HNP_SUPPORT\n");
+01427                         if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
+01428                                 pcd->a_hnp_support = 1;
+01429                                 dwc_otg_pcd_update_otg(pcd, 0);
+01430                         } else {
+01431                                 ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
+01432                         }
+01433                         break;
+01434 
+01435                 case UF_DEVICE_A_ALT_HNP_SUPPORT:
+01436                         /* other RH port does */
+01437                         DWC_DEBUGPL(DBG_PCDV,
+01438                                     "SET_FEATURE: USB_DEVICE_A_ALT_HNP_SUPPORT\n");
+01439                         if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) {
+01440                                 pcd->a_alt_hnp_support = 1;
+01441                                 dwc_otg_pcd_update_otg(pcd, 0);
+01442                         } else {
+01443                                 ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
+01444                         }
+01445                         break;
+01446                 }
+01447                 do_setup_in_status_phase(pcd);
+01448                 break;
+01449 
+01450         case UT_INTERFACE:
+01451                 do_gadget_setup(pcd, &ctrl);
+01452                 break;
+01453 
+01454         case UT_ENDPOINT:
+01455                 if (UGETW(ctrl.wValue) == UF_ENDPOINT_HALT) {
+01456                         ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
+01457                         if (ep == 0) {
+01458                                 ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
+01459                                 return;
+01460                         }
+01461                         ep->stopped = 1;
+01462                         dwc_otg_ep_set_stall(core_if, &ep->dwc_ep);
+01463                 }
+01464                 do_setup_in_status_phase(pcd);
+01465                 break;
+01466         }
+01467 }
+01468 
+01472 static inline void do_clear_feature(dwc_otg_pcd_t * pcd)
+01473 {
+01474         usb_device_request_t ctrl = pcd->setup_pkt->req;
+01475         dwc_otg_pcd_ep_t *ep = 0;
+01476 
+01477         DWC_DEBUGPL(DBG_PCD,
+01478                     "CLEAR_FEATURE:%02x.%02x v%04x i%04x l%04x\n",
+01479                     ctrl.bmRequestType, ctrl.bRequest,
+01480                     UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
+01481                     UGETW(ctrl.wLength));
+01482 
+01483         switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) {
+01484         case UT_DEVICE:
+01485                 switch (UGETW(ctrl.wValue)) {
+01486                 case UF_DEVICE_REMOTE_WAKEUP:
+01487                         pcd->remote_wakeup_enable = 0;
+01488                         break;
+01489 
+01490                 case UF_TEST_MODE:
+01492                         break;
+01493                 }
+01494                 do_setup_in_status_phase(pcd);
+01495                 break;
+01496 
+01497         case UT_ENDPOINT:
+01498                 ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex));
+01499                 if (ep == 0) {
+01500                         ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED);
+01501                         return;
+01502                 }
+01503 
+01504                 pcd_clear_halt(pcd, ep);
+01505 
+01506                 break;
+01507         }
+01508 }
+01509 
+01513 static inline void do_set_address(dwc_otg_pcd_t * pcd)
+01514 {
+01515         dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
+01516         usb_device_request_t ctrl = pcd->setup_pkt->req;
+01517 
+01518         if (ctrl.bmRequestType == UT_DEVICE) {
+01519                 dcfg_data_t dcfg = {.d32 = 0 };
+01520 
+01521 #ifdef DEBUG_EP0
+01522 //                      DWC_DEBUGPL(DBG_PCDV, "SET_ADDRESS:%d\n", ctrl.wValue);
+01523 #endif
+01524                 dcfg.b.devaddr = UGETW(ctrl.wValue);
+01525                 dwc_modify_reg32(&dev_if->dev_global_regs->dcfg, 0, dcfg.d32);
+01526                 do_setup_in_status_phase(pcd);
+01527         }
+01528 }
+01529 
+01580 static inline void pcd_setup(dwc_otg_pcd_t * pcd)
+01581 {
+01582         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+01583         dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+01584         usb_device_request_t ctrl = pcd->setup_pkt->req;
+01585         dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
+01586 
+01587         deptsiz0_data_t doeptsize0 = {.d32 = 0 };
+01588 
+01589 #ifdef DWC_UTE_CFI
+01590         int retval = 0;
+01591         struct cfi_usb_ctrlrequest cfi_req;
+01592 #endif
+01593 
+01594 #ifdef DEBUG_EP0
+01595         DWC_DEBUGPL(DBG_PCD, "SETUP %02x.%02x v%04x i%04x l%04x\n",
+01596                     ctrl.bmRequestType, ctrl.bRequest,
+01597                     UGETW(ctrl.wValue), UGETW(ctrl.wIndex),
+01598                     UGETW(ctrl.wLength));
+01599 #endif
+01600 
+01601         doeptsize0.d32 = dwc_read_reg32(&dev_if->out_ep_regs[0]->doeptsiz);
+01602 
+01605         if (core_if->dma_enable && core_if->dma_desc_enable == 0
+01606             && (doeptsize0.b.supcnt < 2)) {
+01607                 DWC_ERROR
+01608                     ("\n\n-----------    CANNOT handle > 1 setup packet in DMA mode\n\n");
+01609         }
+01610 
+01611         /* Clean up the request queue */
+01612         dwc_otg_request_nuke(ep0);
+01613         ep0->stopped = 0;
+01614 
+01615         if (ctrl.bmRequestType & UE_DIR_IN) {
+01616                 ep0->dwc_ep.is_in = 1;
+01617                 pcd->ep0state = EP0_IN_DATA_PHASE;
+01618         } else {
+01619                 ep0->dwc_ep.is_in = 0;
+01620                 pcd->ep0state = EP0_OUT_DATA_PHASE;
+01621         }
+01622 
+01623         if (UGETW(ctrl.wLength) == 0) {
+01624                 ep0->dwc_ep.is_in = 1;
+01625                 pcd->ep0state = EP0_IN_STATUS_PHASE;
+01626         }
+01627 
+01628         if (UT_GET_TYPE(ctrl.bmRequestType) != UT_STANDARD) {
+01629 
+01630 #ifdef DWC_UTE_CFI
+01631                 DWC_MEMCPY(&cfi_req, &ctrl, sizeof(usb_device_request_t));
+01632 
+01633                 //printk(KERN_ALERT "CFI: req_type=0x%02x; req=0x%02x\n", ctrl.bRequestType, ctrl.bRequest);
+01634                 if (UT_GET_TYPE(cfi_req.bRequestType) == UT_VENDOR) {
+01635                         if (cfi_req.bRequest > 0xB0 && cfi_req.bRequest < 0xBF) {
+01636                                 retval = cfi_setup(pcd, &cfi_req);
+01637                                 if (retval < 0) {
+01638                                         ep0_do_stall(pcd, retval);
+01639                                         pcd->ep0_pending = 0;
+01640                                         return;
+01641                                 }
+01642 
+01643                                 /* if need gadget setup then call it and check the retval */
+01644                                 if (pcd->cfi->need_gadget_att) {
+01645                                         retval =
+01646                                             cfi_gadget_setup(pcd,
+01647                                                              &pcd->cfi->
+01648                                                              ctrl_req);
+01649                                         if (retval < 0) {
+01650                                                 pcd->ep0_pending = 0;
+01651                                                 return;
+01652                                         }
+01653                                 }
+01654 
+01655                                 if (pcd->cfi->need_status_in_complete) {
+01656                                         do_setup_in_status_phase(pcd);
+01657                                 }
+01658                                 return;
+01659                         }
+01660                 }
+01661 #endif
+01662 
+01663                 /* handle non-standard (class/vendor) requests in the gadget driver */
+01664                 do_gadget_setup(pcd, &ctrl);
+01665                 return;
+01666         }
+01667 
+01670 
+01671 
+01672 
+01673         switch (ctrl.bRequest) {
+01674         case UR_GET_STATUS:
+01675                 do_get_status(pcd);
+01676                 break;
+01677 
+01678         case UR_CLEAR_FEATURE:
+01679                 do_clear_feature(pcd);
+01680                 break;
+01681 
+01682         case UR_SET_FEATURE:
+01683                 do_set_feature(pcd);
+01684                 break;
+01685 
+01686         case UR_SET_ADDRESS:
+01687                 do_set_address(pcd);
+01688                 break;
+01689 
+01690         case UR_SET_INTERFACE:
+01691         case UR_SET_CONFIG:
+01692 //              _pcd->request_config = 1;       /* Configuration changed */
+01693                 do_gadget_setup(pcd, &ctrl);
+01694                 break;
+01695 
+01696         case UR_SYNCH_FRAME:
+01697                 do_gadget_setup(pcd, &ctrl);
+01698                 break;
+01699 
+01700         default:
+01701                 /* Call the Gadget Driver's setup functions */
+01702                 do_gadget_setup(pcd, &ctrl);
+01703                 break;
+01704         }
+01705 }
+01706 
+01710 static int32_t ep0_complete_request(dwc_otg_pcd_ep_t * ep)
+01711 {
+01712         dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
+01713         dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+01714         dwc_otg_dev_in_ep_regs_t *in_ep_regs =
+01715             dev_if->in_ep_regs[ep->dwc_ep.num];
+01716 #ifdef DEBUG_EP0
+01717         dwc_otg_dev_out_ep_regs_t *out_ep_regs =
+01718             dev_if->out_ep_regs[ep->dwc_ep.num];
+01719 #endif
+01720         deptsiz0_data_t deptsiz;
+01721         dev_dma_desc_sts_t desc_sts;
+01722         dwc_otg_pcd_request_t *req;
+01723         int is_last = 0;
+01724         dwc_otg_pcd_t *pcd = ep->pcd;
+01725 
+01726 #ifdef DWC_UTE_CFI
+01727         struct cfi_usb_ctrlrequest *ctrlreq;
+01728         int retval = -DWC_E_NOT_SUPPORTED;
+01729 #endif
+01730 
+01731         if (pcd->ep0_pending && DWC_CIRCLEQ_EMPTY(&ep->queue)) {
+01732                 if (ep->dwc_ep.is_in) {
+01733 #ifdef DEBUG_EP0
+01734                         DWC_DEBUGPL(DBG_PCDV, "Do setup OUT status phase\n");
+01735 #endif
+01736                         do_setup_out_status_phase(pcd);
+01737                 } else {
+01738 #ifdef DEBUG_EP0
+01739                         DWC_DEBUGPL(DBG_PCDV, "Do setup IN status phase\n");
+01740 #endif
+01741 
+01742 #ifdef DWC_UTE_CFI
+01743                         ctrlreq = &pcd->cfi->ctrl_req;
+01744 
+01745                         if (UT_GET_TYPE(ctrlreq->bRequestType) == UT_VENDOR) {
+01746                                 if (ctrlreq->bRequest > 0xB0
+01747                                     && ctrlreq->bRequest < 0xBF) {
+01748 
+01749                                         /* Return if the PCD failed to handle the request */
+01750                                         if ((retval =
+01751                                              pcd->cfi->ops.
+01752                                              ctrl_write_complete(pcd->cfi,
+01753                                                                  pcd)) < 0) {
+01754                                                 CFI_INFO
+01755                                                     ("ERROR setting a new value in the PCD(%d)\n",
+01756                                                      retval);
+01757                                                 ep0_do_stall(pcd, retval);
+01758                                                 pcd->ep0_pending = 0;
+01759                                                 return 0;
+01760                                         }
+01761 
+01762                                         /* If the gadget needs to be notified on the request */
+01763                                         if (pcd->cfi->need_gadget_att == 1) {
+01764                                                 //retval = do_gadget_setup(pcd, &pcd->cfi->ctrl_req);
+01765                                                 retval =
+01766                                                     cfi_gadget_setup(pcd,
+01767                                                                      &pcd->cfi->
+01768                                                                      ctrl_req);
+01769 
+01770                                                 /* Return from the function if the gadget failed to process
+01771                                                  * the request properly - this should never happen !!!
+01772                                                  */
+01773                                                 if (retval < 0) {
+01774                                                         CFI_INFO
+01775                                                             ("ERROR setting a new value in the gadget(%d)\n",
+01776                                                              retval);
+01777                                                         pcd->ep0_pending = 0;
+01778                                                         return 0;
+01779                                                 }
+01780                                         }
+01781 
+01782                                         CFI_INFO("%s: RETVAL=%d\n", __func__,
+01783                                                  retval);
+01784                                         /* If we hit here then the PCD and the gadget has properly
+01785                                          * handled the request - so send the ZLP IN to the host.
+01786                                          */
+01787                                         /* @todo: MAS - decide whether we need to start the setup
+01788                                          * stage based on the need_setup value of the cfi object
+01789                                          */
+01790                                         do_setup_in_status_phase(pcd);
+01791                                         pcd->ep0_pending = 0;
+01792                                         return 1;
+01793                                 }
+01794                         }
+01795 #endif
+01796 
+01797                         do_setup_in_status_phase(pcd);
+01798                 }
+01799                 pcd->ep0_pending = 0;
+01800                 return 1;
+01801         }
+01802 
+01803         if (DWC_CIRCLEQ_EMPTY(&ep->queue)) {
+01804                 return 0;
+01805         }
+01806         req = DWC_CIRCLEQ_FIRST(&ep->queue);
+01807 
+01808         if (pcd->ep0state == EP0_OUT_STATUS_PHASE
+01809             || pcd->ep0state == EP0_IN_STATUS_PHASE) {
+01810                 is_last = 1;
+01811         } else if (ep->dwc_ep.is_in) {
+01812                 deptsiz.d32 = dwc_read_reg32(&in_ep_regs->dieptsiz);
+01813                 if (core_if->dma_desc_enable != 0)
+01814                         desc_sts = dev_if->in_desc_addr->status;
+01815 #ifdef DEBUG_EP0
+01816                 DWC_DEBUGPL(DBG_PCDV, "%d len=%d  xfersize=%d pktcnt=%d\n",
+01817                             ep->dwc_ep.num, ep->dwc_ep.xfer_len,
+01818                             deptsiz.b.xfersize, deptsiz.b.pktcnt);
+01819 #endif
+01820 
+01821                 if (((core_if->dma_desc_enable == 0)
+01822                      && (deptsiz.b.xfersize == 0))
+01823                     || ((core_if->dma_desc_enable != 0)
+01824                         && (desc_sts.b.bytes == 0))) {
+01825                         req->actual = ep->dwc_ep.xfer_count;
+01826                         /* Is a Zero Len Packet needed? */
+01827                         if (req->sent_zlp) {
+01828 #ifdef DEBUG_EP0
+01829                                 DWC_DEBUGPL(DBG_PCD, "Setup Rx ZLP\n");
+01830 #endif
+01831                                 req->sent_zlp = 0;
+01832                         }
+01833                         do_setup_out_status_phase(pcd);
+01834                 }
+01835         } else {
+01836                 /* ep0-OUT */
+01837 #ifdef DEBUG_EP0
+01838                 deptsiz.d32 = dwc_read_reg32(&out_ep_regs->doeptsiz);
+01839                 DWC_DEBUGPL(DBG_PCDV, "%d len=%d xsize=%d pktcnt=%d\n",
+01840                             ep->dwc_ep.num, ep->dwc_ep.xfer_len,
+01841                             deptsiz.b.xfersize, deptsiz.b.pktcnt);
+01842 #endif
+01843                 req->actual = ep->dwc_ep.xfer_count;
+01844 
+01845                 /* Is a Zero Len Packet needed? */
+01846                 if (req->sent_zlp) {
+01847 #ifdef DEBUG_EP0
+01848                         DWC_DEBUGPL(DBG_PCDV, "Setup Tx ZLP\n");
+01849 #endif
+01850                         req->sent_zlp = 0;
+01851                 }
+01852                 if (core_if->dma_desc_enable == 0)
+01853                         do_setup_in_status_phase(pcd);
+01854         }
+01855 
+01856         /* Complete the request */
+01857         if (is_last) {
+01858                 dwc_otg_request_done(ep, req, 0);
+01859                 ep->dwc_ep.start_xfer_buff = 0;
+01860                 ep->dwc_ep.xfer_buff = 0;
+01861                 ep->dwc_ep.xfer_len = 0;
+01862                 return 1;
+01863         }
+01864         return 0;
+01865 }
+01866 
+01867 #ifdef DWC_UTE_CFI
+01868 
+01874 static inline int cfi_calc_desc_residue(dwc_otg_pcd_ep_t * ep)
+01875 {
+01876         int32_t ret = 0;
+01877         int i;
+01878         struct dwc_otg_dma_desc *ddesc = NULL;
+01879         struct cfi_ep *cfiep;
+01880 
+01881         /* See if the pcd_ep has its respective cfi_ep mapped */
+01882         cfiep = get_cfi_ep_by_pcd_ep(ep->pcd->cfi, ep);
+01883         if (!cfiep) {
+01884                 CFI_INFO("%s: Failed to find ep\n", __func__);
+01885                 return -1;
+01886         }
+01887 
+01888         ddesc = ep->dwc_ep.descs;
+01889 
+01890         for (i = 0; (i < cfiep->desc_count) && (i < MAX_DMA_DESCS_PER_EP); i++) {
+01891 
+01892 #if defined(PRINT_CFI_DMA_DESCS)
+01893                 print_desc(ddesc, ep->ep.name, i);
+01894 #endif
+01895                 ret += ddesc->status.b.bytes;
+01896                 ddesc++;
+01897         }
+01898 
+01899         if (ret)
+01900                 CFI_INFO("!!!!!!!!!! WARNING (%s) - residue=%d\n", __func__,
+01901                          ret);
+01902 
+01903         return ret;
+01904 }
+01905 #endif
+01906 
+01911 static void complete_ep(dwc_otg_pcd_ep_t * ep)
+01912 {
+01913         dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
+01914         dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+01915         dwc_otg_dev_in_ep_regs_t *in_ep_regs =
+01916             dev_if->in_ep_regs[ep->dwc_ep.num];
+01917         deptsiz_data_t deptsiz;
+01918         dev_dma_desc_sts_t desc_sts;
+01919         dwc_otg_pcd_request_t *req = 0;
+01920         dwc_otg_dev_dma_desc_t *dma_desc;
+01921         uint32_t byte_count = 0;
+01922         int is_last = 0;
+01923         int i;
+01924 
+01925         DWC_DEBUGPL(DBG_PCDV, "%s() %d-%s\n", __func__, ep->dwc_ep.num,
+01926                     (ep->dwc_ep.is_in ? "IN" : "OUT"));
+01927 
+01928         /* Get any pending requests */
+01929         if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) {
+01930                 req = DWC_CIRCLEQ_FIRST(&ep->queue);
+01931                 if (!req) {
+01932                         DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep);
+01933                         return;
+01934                 }
+01935         } else {
+01936                 DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep);
+01937                 return;
+01938         }
+01939 
+01940         DWC_DEBUGPL(DBG_PCD, "Requests %d\n", ep->pcd->request_pending);
+01941 
+01942         if (ep->dwc_ep.is_in) {
+01943                 deptsiz.d32 = dwc_read_reg32(&in_ep_regs->dieptsiz);
+01944 
+01945                 if (core_if->dma_enable) {
+01946                         if (core_if->dma_desc_enable == 0) {
+01947                                 if (deptsiz.b.xfersize == 0
+01948                                     && deptsiz.b.pktcnt == 0) {
+01949                                         byte_count =
+01950                                             ep->dwc_ep.xfer_len -
+01951                                             ep->dwc_ep.xfer_count;
+01952 
+01953                                         ep->dwc_ep.xfer_buff += byte_count;
+01954                                         ep->dwc_ep.dma_addr += byte_count;
+01955                                         ep->dwc_ep.xfer_count += byte_count;
+01956 
+01957                                         DWC_DEBUGPL(DBG_PCDV,
+01958                                                     "%d-%s len=%d  xfersize=%d pktcnt=%d\n",
+01959                                                     ep->dwc_ep.num,
+01960                                                     (ep->dwc_ep.
+01961                                                      is_in ? "IN" : "OUT"),
+01962                                                     ep->dwc_ep.xfer_len,
+01963                                                     deptsiz.b.xfersize,
+01964                                                     deptsiz.b.pktcnt);
+01965 
+01966                                         if (ep->dwc_ep.xfer_len <
+01967                                             ep->dwc_ep.total_len) {
+01968                                                 dwc_otg_ep_start_transfer
+01969                                                     (core_if, &ep->dwc_ep);
+01970                                         } else if (ep->dwc_ep.sent_zlp) {
+01971                                                 /*      
+01972                                                  * This fragment of code should initiate 0 
+01973                                                  * length trasfer in case if it is queued
+01974                                                  * a trasfer with size divisible to EPs max 
+01975                                                  * packet size and with usb_request zero field 
+01976                                                  * is set, which means that after data is transfered, 
+01977                                                  * it is also should be transfered 
+01978                                                  * a 0 length packet at the end. For Slave and 
+01979                                                  * Buffer DMA modes in this case SW has 
+01980                                                  * to initiate 2 transfers one with transfer size, 
+01981                                                  * and the second with 0 size. For Desriptor 
+01982                                                  * DMA mode SW is able to initiate a transfer, 
+01983                                                  * which will handle all the packets including 
+01984                                                  * the last  0 legth.
+01985                                                  */
+01986                                                 ep->dwc_ep.sent_zlp = 0;
+01987                                                 dwc_otg_ep_start_zl_transfer
+01988                                                     (core_if, &ep->dwc_ep);
+01989                                         } else {
+01990                                                 is_last = 1;
+01991                                         }
+01992                                 } else {
+01993                                         DWC_WARN
+01994                                             ("Incomplete transfer (%d - %s [siz=%d pkt=%d])\n",
+01995                                              ep->dwc_ep.num,
+01996                                              (ep->dwc_ep.is_in ? "IN" : "OUT"),
+01997                                              deptsiz.b.xfersize,
+01998                                              deptsiz.b.pktcnt);
+01999                                 }
+02000                         } else {
+02001                                 dma_desc = ep->dwc_ep.desc_addr;
+02002                                 byte_count = 0;
+02003                                 ep->dwc_ep.sent_zlp = 0;
+02004 
+02005 #ifdef DWC_UTE_CFI
+02006                                 CFI_INFO("%s: BUFFER_MODE=%d\n", __func__,
+02007                                          ep->dwc_ep.buff_mode);
+02008                                 if (ep->dwc_ep.buff_mode != BM_STANDARD) {
+02009                                         int residue;
+02010 
+02011                                         residue = cfi_calc_desc_residue(ep);
+02012                                         if (residue < 0)
+02013                                                 return;
+02014 
+02015                                         byte_count = residue;
+02016                                 } else {
+02017 #endif
+02018                                         for (i = 0; i < ep->dwc_ep.desc_cnt;
+02019                                              ++i) {
+02020                                         desc_sts = dma_desc->status;
+02021                                         byte_count += desc_sts.b.bytes;
+02022                                         dma_desc++;
+02023                                 }
+02024 #ifdef DWC_UTE_CFI
+02025                                 }
+02026 #endif
+02027                                 if (byte_count == 0) {
+02028                                         ep->dwc_ep.xfer_count =
+02029                                             ep->dwc_ep.total_len;
+02030                                         is_last = 1;
+02031                                 } else {
+02032                                         DWC_WARN("Incomplete transfer\n");
+02033                                 }
+02034                         }
+02035                 } else {
+02036                         if (deptsiz.b.xfersize == 0 && deptsiz.b.pktcnt == 0) {
+02037                                 DWC_DEBUGPL(DBG_PCDV,
+02038                                             "%d-%s len=%d  xfersize=%d pktcnt=%d\n",
+02039                                             ep->dwc_ep.num,
+02040                                             ep->dwc_ep.is_in ? "IN" : "OUT",
+02041                                             ep->dwc_ep.xfer_len,
+02042                                             deptsiz.b.xfersize,
+02043                                             deptsiz.b.pktcnt);
+02044 
+02045                                 /*      Check if the whole transfer was completed,  
+02046                                  *      if no, setup transfer for next portion of data
+02047                                  */
+02048                                 if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
+02049                                         dwc_otg_ep_start_transfer(core_if,
+02050                                                                   &ep->dwc_ep);
+02051                                 } else if (ep->dwc_ep.sent_zlp) {
+02052                                         /*      
+02053                                          * This fragment of code should initiate 0 
+02054                                          * length trasfer in case if it is queued
+02055                                          * a trasfer with size divisible to EPs max 
+02056                                          * packet size and with usb_request zero field 
+02057                                          * is set, which means that after data is transfered, 
+02058                                          * it is also should be transfered 
+02059                                          * a 0 length packet at the end. For Slave and 
+02060                                          * Buffer DMA modes in this case SW has 
+02061                                          * to initiate 2 transfers one with transfer size, 
+02062                                          * and the second with 0 size. For Desriptor 
+02063                                          * DMA mode SW is able to initiate a transfer, 
+02064                                          * which will handle all the packets including 
+02065                                          * the last  0 legth.
+02066                                          */
+02067                                         ep->dwc_ep.sent_zlp = 0;
+02068                                         dwc_otg_ep_start_zl_transfer(core_if,
+02069                                                                      &ep->
+02070                                                                      dwc_ep);
+02071                                 } else {
+02072                                         is_last = 1;
+02073                                 }
+02074                         } else {
+02075                                 DWC_WARN
+02076                                     ("Incomplete transfer (%d-%s [siz=%d pkt=%d])\n",
+02077                                      ep->dwc_ep.num,
+02078                                      (ep->dwc_ep.is_in ? "IN" : "OUT"),
+02079                                      deptsiz.b.xfersize, deptsiz.b.pktcnt);
+02080                         }
+02081                 }
+02082         } else {
+02083                 dwc_otg_dev_out_ep_regs_t *out_ep_regs =
+02084                     dev_if->out_ep_regs[ep->dwc_ep.num];
+02085                 desc_sts.d32 = 0;
+02086                 if (core_if->dma_enable) {
+02087                         if (core_if->dma_desc_enable) {
+02088                                 dma_desc = ep->dwc_ep.desc_addr;
+02089                                 byte_count = 0;
+02090                                 ep->dwc_ep.sent_zlp = 0;
+02091 
+02092 #ifdef DWC_UTE_CFI
+02093                                 CFI_INFO("%s: BUFFER_MODE=%d\n", __func__,
+02094                                          ep->dwc_ep.buff_mode);
+02095                                 if (ep->dwc_ep.buff_mode != BM_STANDARD) {
+02096                                         int residue;
+02097                                         residue = cfi_calc_desc_residue(ep);
+02098                                         if (residue < 0)
+02099                                                 return;
+02100                                         byte_count = residue;
+02101                                 } else {
+02102 #endif
+02103 
+02104                                         for (i = 0; i < ep->dwc_ep.desc_cnt;
+02105                                              ++i) {
+02106                                         desc_sts = dma_desc->status;
+02107                                         byte_count += desc_sts.b.bytes;
+02108                                         dma_desc++;
+02109                                 }
+02110 
+02111 #ifdef DWC_UTE_CFI
+02112                                 }
+02113 #endif
+02114                                 ep->dwc_ep.xfer_count = ep->dwc_ep.total_len
+02115                                     - byte_count +
+02116                                     ((4 - (ep->dwc_ep.total_len & 0x3)) & 0x3);
+02117                                 is_last = 1;
+02118                         } else {
+02119                                 deptsiz.d32 = 0;
+02120                                 deptsiz.d32 =
+02121                                     dwc_read_reg32(&out_ep_regs->doeptsiz);
+02122 
+02123                                 byte_count = (ep->dwc_ep.xfer_len -
+02124                                               ep->dwc_ep.xfer_count -
+02125                                               deptsiz.b.xfersize);
+02126                                 ep->dwc_ep.xfer_buff += byte_count;
+02127                                 ep->dwc_ep.dma_addr += byte_count;
+02128                                 ep->dwc_ep.xfer_count += byte_count;
+02129 
+02130                                 /*      Check if the whole transfer was completed,  
+02131                                  *      if no, setup transfer for next portion of data
+02132                                  */
+02133                                 if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
+02134                                         dwc_otg_ep_start_transfer(core_if,
+02135                                                                   &ep->dwc_ep);
+02136                                 } else if (ep->dwc_ep.sent_zlp) {
+02137                                         /*      
+02138                                          * This fragment of code should initiate 0 
+02139                                          * length trasfer in case if it is queued
+02140                                          * a trasfer with size divisible to EPs max 
+02141                                          * packet size and with usb_request zero field 
+02142                                          * is set, which means that after data is transfered, 
+02143                                          * it is also should be transfered 
+02144                                          * a 0 length packet at the end. For Slave and 
+02145                                          * Buffer DMA modes in this case SW has 
+02146                                          * to initiate 2 transfers one with transfer size, 
+02147                                          * and the second with 0 size. For Desriptor 
+02148                                          * DMA mode SW is able to initiate a transfer, 
+02149                                          * which will handle all the packets including 
+02150                                          * the last  0 legth.
+02151                                          */
+02152                                         ep->dwc_ep.sent_zlp = 0;
+02153                                         dwc_otg_ep_start_zl_transfer(core_if,
+02154                                                                      &ep->
+02155                                                                      dwc_ep);
+02156                                 } else {
+02157                                         is_last = 1;
+02158                                 }
+02159                         }
+02160                 } else {
+02161                         /*      Check if the whole transfer was completed,  
+02162                          *      if no, setup transfer for next portion of data
+02163                          */
+02164                         if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) {
+02165                                 dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
+02166                         } else if (ep->dwc_ep.sent_zlp) {
+02167                                 /*      
+02168                                  * This fragment of code should initiate 0 
+02169                                  * length trasfer in case if it is queued
+02170                                  * a trasfer with size divisible to EPs max 
+02171                                  * packet size and with usb_request zero field 
+02172                                  * is set, which means that after data is transfered, 
+02173                                  * it is also should be transfered 
+02174                                  * a 0 length packet at the end. For Slave and 
+02175                                  * Buffer DMA modes in this case SW has 
+02176                                  * to initiate 2 transfers one with transfer size, 
+02177                                  * and the second with 0 size. For Desriptor 
+02178                                  * DMA mode SW is able to initiate a transfer, 
+02179                                  * which will handle all the packets including 
+02180                                  * the last  0 legth.
+02181                                  */
+02182                                 ep->dwc_ep.sent_zlp = 0;
+02183                                 dwc_otg_ep_start_zl_transfer(core_if,
+02184                                                              &ep->dwc_ep);
+02185                         } else {
+02186                                 is_last = 1;
+02187                         }
+02188                 }
+02189 
+02190                 DWC_DEBUGPL(DBG_PCDV,
+02191                             "addr %p,    %d-%s len=%d cnt=%d xsize=%d pktcnt=%d\n",
+02192                             &out_ep_regs->doeptsiz, ep->dwc_ep.num,
+02193                             ep->dwc_ep.is_in ? "IN" : "OUT",
+02194                             ep->dwc_ep.xfer_len, ep->dwc_ep.xfer_count,
+02195                             deptsiz.b.xfersize, deptsiz.b.pktcnt);
+02196         }
+02197 
+02198         /* Complete the request */
+02199         if (is_last) {
+02200 #ifdef DWC_UTE_CFI
+02201                 if (ep->dwc_ep.buff_mode != BM_STANDARD) {
+02202                         req->actual = ep->dwc_ep.cfi_req_len - byte_count;
+02203                 } else {
+02204 #endif
+02205                 req->actual = ep->dwc_ep.xfer_count;
+02206 #ifdef DWC_UTE_CFI
+02207                 }
+02208 #endif
+02209 
+02210                 dwc_otg_request_done(ep, req, 0);
+02211 
+02212                 ep->dwc_ep.start_xfer_buff = 0;
+02213                 ep->dwc_ep.xfer_buff = 0;
+02214                 ep->dwc_ep.xfer_len = 0;
+02215 
+02216                 /* If there is a request in the queue start it. */
+02217                 start_next_request(ep);
+02218         }
+02219 }
+02220 
+02221 #ifdef DWC_EN_ISOC
+02222 
+02227 static void dwc_otg_pcd_handle_iso_bna(dwc_otg_pcd_ep_t * ep)
+02228 {
+02229         dwc_ep_t *dwc_ep = &ep->dwc_ep;
+02230         volatile uint32_t *addr;
+02231         depctl_data_t depctl = {.d32 = 0 };
+02232         dwc_otg_pcd_t *pcd = ep->pcd;
+02233         dwc_otg_dev_dma_desc_t *dma_desc;
+02234         int i;
+02235 
+02236         dma_desc =
+02237             dwc_ep->iso_desc_addr + dwc_ep->desc_cnt * (dwc_ep->proc_buf_num);
+02238 
+02239         if (dwc_ep->is_in) {
+02240                 dev_dma_desc_sts_t sts = {.d32 = 0 };
+02241                 for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
+02242                         sts.d32 = dma_desc->status.d32;
+02243                         sts.b_iso_in.bs = BS_HOST_READY;
+02244                         dma_desc->status.d32 = sts.d32;
+02245                 }
+02246         } else {
+02247                 dev_dma_desc_sts_t sts = {.d32 = 0 };
+02248                 for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) {
+02249                         sts.d32 = dma_desc->status.d32;
+02250                         sts.b_iso_out.bs = BS_HOST_READY;
+02251                         dma_desc->status.d32 = sts.d32;
+02252                 }
+02253         }
+02254 
+02255         if (dwc_ep->is_in == 0) {
+02256                 addr =
+02257                     &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->num]->
+02258                     doepctl;
+02259         } else {
+02260                 addr =
+02261                     &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
+02262         }
+02263         depctl.b.epena = 1;
+02264         dwc_modify_reg32(addr, depctl.d32, depctl.d32);
+02265 }
+02266 
+02274 void set_current_pkt_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+02275 {
+02276         deptsiz_data_t deptsiz = {.d32 = 0 };
+02277         dma_addr_t dma_addr;
+02278         uint32_t offset;
+02279 
+02280         if (ep->proc_buf_num)
+02281                 dma_addr = ep->dma_addr1;
+02282         else
+02283                 dma_addr = ep->dma_addr0;
+02284 
+02285         if (ep->is_in) {
+02286                 deptsiz.d32 =
+02287                     dwc_read_reg32(&core_if->dev_if->in_ep_regs[ep->num]->
+02288                                    dieptsiz);
+02289                 offset = ep->data_per_frame;
+02290         } else {
+02291                 deptsiz.d32 =
+02292                     dwc_read_reg32(&core_if->dev_if->out_ep_regs[ep->num]->
+02293                                    doeptsiz);
+02294                 offset =
+02295                     ep->data_per_frame +
+02296                     (0x4 & (0x4 - (ep->data_per_frame & 0x3)));
+02297         }
+02298 
+02299         if (!deptsiz.b.xfersize) {
+02300                 ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame;
+02301                 ep->pkt_info[ep->cur_pkt].offset =
+02302                     ep->cur_pkt_dma_addr - dma_addr;
+02303                 ep->pkt_info[ep->cur_pkt].status = 0;
+02304         } else {
+02305                 ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame;
+02306                 ep->pkt_info[ep->cur_pkt].offset =
+02307                     ep->cur_pkt_dma_addr - dma_addr;
+02308                 ep->pkt_info[ep->cur_pkt].status = -DWC_E_NO_DATA;
+02309         }
+02310         ep->cur_pkt_addr += offset;
+02311         ep->cur_pkt_dma_addr += offset;
+02312         ep->cur_pkt++;
+02313 }
+02314 
+02322 static void set_ddma_iso_pkts_info(dwc_otg_core_if_t * core_if,
+02323                                    dwc_ep_t * dwc_ep)
+02324 {
+02325         dwc_otg_dev_dma_desc_t *dma_desc;
+02326         dev_dma_desc_sts_t sts = {.d32 = 0 };
+02327         iso_pkt_info_t *iso_packet;
+02328         uint32_t data_per_desc;
+02329         uint32_t offset;
+02330         int i, j;
+02331 
+02332         iso_packet = dwc_ep->pkt_info;
+02333 
+02336         if (dwc_ep->is_in == 0) {
+02337                 dma_desc =
+02338                     dwc_ep->iso_desc_addr +
+02339                     dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
+02340                 offset = 0;
+02341 
+02342                 for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
+02343                      i += dwc_ep->pkt_per_frm) {
+02344                         for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
+02345                                 data_per_desc =
+02346                                     ((j + 1) * dwc_ep->maxpacket >
+02347                                      dwc_ep->data_per_frame) ? dwc_ep->
+02348                                     data_per_frame -
+02349                                     j * dwc_ep->maxpacket : dwc_ep->maxpacket;
+02350                                 data_per_desc +=
+02351                                     (data_per_desc % 4) ? (4 -
+02352                                                            data_per_desc %
+02353                                                            4) : 0;
+02354 
+02355                                 sts.d32 = dma_desc->status.d32;
+02356 
+02357                                 /* Write status in iso_packet_decsriptor  */
+02358                                 iso_packet->status =
+02359                                     sts.b_iso_out.rxsts +
+02360                                     (sts.b_iso_out.bs ^ BS_DMA_DONE);
+02361                                 if (iso_packet->status) {
+02362                                         iso_packet->status = -DWC_E_NO_DATA;
+02363                                 }
+02364 
+02365                                 /* Received data length */
+02366                                 if (!sts.b_iso_out.rxbytes) {
+02367                                         iso_packet->length =
+02368                                             data_per_desc -
+02369                                             sts.b_iso_out.rxbytes;
+02370                                 } else {
+02371                                         iso_packet->length =
+02372                                             data_per_desc -
+02373                                             sts.b_iso_out.rxbytes + (4 -
+02374                                                                      dwc_ep->
+02375                                                                      data_per_frame
+02376                                                                      % 4);
+02377                                 }
+02378 
+02379                                 iso_packet->offset = offset;
+02380 
+02381                                 offset += data_per_desc;
+02382                                 dma_desc++;
+02383                                 iso_packet++;
+02384                         }
+02385                 }
+02386 
+02387                 for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
+02388                         data_per_desc =
+02389                             ((j + 1) * dwc_ep->maxpacket >
+02390                              dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
+02391                             j * dwc_ep->maxpacket : dwc_ep->maxpacket;
+02392                         data_per_desc +=
+02393                             (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
+02394 
+02395                         sts.d32 = dma_desc->status.d32;
+02396 
+02397                         /* Write status in iso_packet_decsriptor  */
+02398                         iso_packet->status =
+02399                             sts.b_iso_out.rxsts +
+02400                             (sts.b_iso_out.bs ^ BS_DMA_DONE);
+02401                         if (iso_packet->status) {
+02402                                 iso_packet->status = -DWC_E_NO_DATA;
+02403                         }
+02404 
+02405                         /* Received data length */
+02406                         iso_packet->length =
+02407                             dwc_ep->data_per_frame - sts.b_iso_out.rxbytes;
+02408 
+02409                         iso_packet->offset = offset;
+02410 
+02411                         offset += data_per_desc;
+02412                         iso_packet++;
+02413                         dma_desc++;
+02414                 }
+02415 
+02416                 sts.d32 = dma_desc->status.d32;
+02417 
+02418                 /* Write status in iso_packet_decsriptor  */
+02419                 iso_packet->status =
+02420                     sts.b_iso_out.rxsts + (sts.b_iso_out.bs ^ BS_DMA_DONE);
+02421                 if (iso_packet->status) {
+02422                         iso_packet->status = -DWC_E_NO_DATA;
+02423                 }
+02424                 /* Received data length */
+02425                 if (!sts.b_iso_out.rxbytes) {
+02426                         iso_packet->length =
+02427                             dwc_ep->data_per_frame - sts.b_iso_out.rxbytes;
+02428                 } else {
+02429                         iso_packet->length =
+02430                             dwc_ep->data_per_frame - sts.b_iso_out.rxbytes +
+02431                             (4 - dwc_ep->data_per_frame % 4);
+02432                 }
+02433 
+02434                 iso_packet->offset = offset;
+02435         } else {
+02438                 dma_desc =
+02439                     dwc_ep->iso_desc_addr +
+02440                     dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
+02441 
+02442                 for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
+02443                         sts.d32 = dma_desc->status.d32;
+02444 
+02445                         /* Write status in iso packet descriptor */
+02446                         iso_packet->status =
+02447                             sts.b_iso_in.txsts +
+02448                             (sts.b_iso_in.bs ^ BS_DMA_DONE);
+02449                         if (iso_packet->status != 0) {
+02450                                 iso_packet->status = -DWC_E_NO_DATA;
+02451 
+02452                         }
+02453                         /* Bytes has been transfered */
+02454                         iso_packet->length =
+02455                             dwc_ep->data_per_frame - sts.b_iso_in.txbytes;
+02456 
+02457                         dma_desc++;
+02458                         iso_packet++;
+02459                 }
+02460 
+02461                 sts.d32 = dma_desc->status.d32;
+02462                 while (sts.b_iso_in.bs == BS_DMA_BUSY) {
+02463                         sts.d32 = dma_desc->status.d32;
+02464                 }
+02465 
+02466                 /* Write status in iso packet descriptor ??? do be done with ERROR codes */
+02467                 iso_packet->status =
+02468                     sts.b_iso_in.txsts + (sts.b_iso_in.bs ^ BS_DMA_DONE);
+02469                 if (iso_packet->status != 0) {
+02470                         iso_packet->status = -DWC_E_NO_DATA;
+02471                 }
+02472 
+02473                 /* Bytes has been transfered */
+02474                 iso_packet->length =
+02475                     dwc_ep->data_per_frame - sts.b_iso_in.txbytes;
+02476         }
+02477 }
+02478 
+02486 static void reinit_ddma_iso_xfer(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep)
+02487 {
+02488         int i, j;
+02489         dwc_otg_dev_dma_desc_t *dma_desc;
+02490         dma_addr_t dma_ad;
+02491         volatile uint32_t *addr;
+02492         dev_dma_desc_sts_t sts = {.d32 = 0 };
+02493         uint32_t data_per_desc;
+02494 
+02495         if (dwc_ep->is_in == 0) {
+02496                 addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl;
+02497         } else {
+02498                 addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl;
+02499         }
+02500 
+02501         if (dwc_ep->proc_buf_num == 0) {
+02503                 dma_ad = dwc_ep->dma_addr0;
+02504         } else {
+02506                 dma_ad = dwc_ep->dma_addr1;
+02507         }
+02508 
+02511         if (dwc_ep->is_in == 0) {
+02512                 dma_desc =
+02513                     dwc_ep->iso_desc_addr +
+02514                     dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
+02515 
+02516                 sts.b_iso_out.bs = BS_HOST_READY;
+02517                 sts.b_iso_out.rxsts = 0;
+02518                 sts.b_iso_out.l = 0;
+02519                 sts.b_iso_out.sp = 0;
+02520                 sts.b_iso_out.ioc = 0;
+02521                 sts.b_iso_out.pid = 0;
+02522                 sts.b_iso_out.framenum = 0;
+02523 
+02524                 for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm;
+02525                      i += dwc_ep->pkt_per_frm) {
+02526                         for (j = 0; j < dwc_ep->pkt_per_frm; ++j) {
+02527                                 data_per_desc =
+02528                                     ((j + 1) * dwc_ep->maxpacket >
+02529                                      dwc_ep->data_per_frame) ? dwc_ep->
+02530                                     data_per_frame -
+02531                                     j * dwc_ep->maxpacket : dwc_ep->maxpacket;
+02532                                 data_per_desc +=
+02533                                     (data_per_desc % 4) ? (4 -
+02534                                                            data_per_desc %
+02535                                                            4) : 0;
+02536                                 sts.b_iso_out.rxbytes = data_per_desc;
+02537                                 dma_desc->buf = dma_ad;
+02538                                 dma_desc->status.d32 = sts.d32;
+02539 
+02540                                 dma_ad += data_per_desc;
+02541                                 dma_desc++;
+02542                         }
+02543                 }
+02544 
+02545                 for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) {
+02546 
+02547                         data_per_desc =
+02548                             ((j + 1) * dwc_ep->maxpacket >
+02549                              dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
+02550                             j * dwc_ep->maxpacket : dwc_ep->maxpacket;
+02551                         data_per_desc +=
+02552                             (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
+02553                         sts.b_iso_out.rxbytes = data_per_desc;
+02554 
+02555                         dma_desc->buf = dma_ad;
+02556                         dma_desc->status.d32 = sts.d32;
+02557 
+02558                         dma_desc++;
+02559                         dma_ad += data_per_desc;
+02560                 }
+02561 
+02562                 sts.b_iso_out.ioc = 1;
+02563                 sts.b_iso_out.l = dwc_ep->proc_buf_num;
+02564 
+02565                 data_per_desc =
+02566                     ((j + 1) * dwc_ep->maxpacket >
+02567                      dwc_ep->data_per_frame) ? dwc_ep->data_per_frame -
+02568                     j * dwc_ep->maxpacket : dwc_ep->maxpacket;
+02569                 data_per_desc +=
+02570                     (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0;
+02571                 sts.b_iso_out.rxbytes = data_per_desc;
+02572 
+02573                 dma_desc->buf = dma_ad;
+02574                 dma_desc->status.d32 = sts.d32;
+02575         } else {
+02578                 dma_desc =
+02579                     dwc_ep->iso_desc_addr +
+02580                     dwc_ep->desc_cnt * dwc_ep->proc_buf_num;
+02581 
+02582                 sts.b_iso_in.bs = BS_HOST_READY;
+02583                 sts.b_iso_in.txsts = 0;
+02584                 sts.b_iso_in.sp = 0;
+02585                 sts.b_iso_in.ioc = 0;
+02586                 sts.b_iso_in.pid = dwc_ep->pkt_per_frm;
+02587                 sts.b_iso_in.framenum = dwc_ep->next_frame;
+02588                 sts.b_iso_in.txbytes = dwc_ep->data_per_frame;
+02589                 sts.b_iso_in.l = 0;
+02590 
+02591                 for (i = 0; i < dwc_ep->desc_cnt - 1; i++) {
+02592                         dma_desc->buf = dma_ad;
+02593                         dma_desc->status.d32 = sts.d32;
+02594 
+02595                         sts.b_iso_in.framenum += dwc_ep->bInterval;
+02596                         dma_ad += dwc_ep->data_per_frame;
+02597                         dma_desc++;
+02598                 }
+02599 
+02600                 sts.b_iso_in.ioc = 1;
+02601                 sts.b_iso_in.l = dwc_ep->proc_buf_num;
+02602 
+02603                 dma_desc->buf = dma_ad;
+02604                 dma_desc->status.d32 = sts.d32;
+02605 
+02606                 dwc_ep->next_frame =
+02607                     sts.b_iso_in.framenum + dwc_ep->bInterval * 1;
+02608         }
+02609         dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1;
+02610 }
+02611 
+02620 static uint32_t handle_iso_out_pkt_dropped(dwc_otg_core_if_t * core_if,
+02621                                            dwc_ep_t * dwc_ep)
+02622 {
+02623         uint32_t dma_addr;
+02624         uint32_t drp_pkt;
+02625         uint32_t drp_pkt_cnt;
+02626         deptsiz_data_t deptsiz = {.d32 = 0 };
+02627         depctl_data_t depctl = {.d32 = 0 };
+02628         int i;
+02629 
+02630         deptsiz.d32 =
+02631             dwc_read_reg32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->
+02632                            doeptsiz);
+02633 
+02634         drp_pkt = dwc_ep->pkt_cnt - deptsiz.b.pktcnt;
+02635         drp_pkt_cnt = dwc_ep->pkt_per_frm - (drp_pkt % dwc_ep->pkt_per_frm);
+02636 
+02637         /* Setting dropped packets status */
+02638         for (i = 0; i < drp_pkt_cnt; ++i) {
+02639                 dwc_ep->pkt_info[drp_pkt].status = -DWC_E_NO_DATA;
+02640                 drp_pkt++;
+02641                 deptsiz.b.pktcnt--;
+02642         }
+02643 
+02644         if (deptsiz.b.pktcnt > 0) {
+02645                 deptsiz.b.xfersize =
+02646                     dwc_ep->xfer_len - (dwc_ep->pkt_cnt -
+02647                                         deptsiz.b.pktcnt) * dwc_ep->maxpacket;
+02648         } else {
+02649                 deptsiz.b.xfersize = 0;
+02650                 deptsiz.b.pktcnt = 0;
+02651         }
+02652 
+02653         dwc_write_reg32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz,
+02654                         deptsiz.d32);
+02655 
+02656         if (deptsiz.b.pktcnt > 0) {
+02657                 if (dwc_ep->proc_buf_num) {
+02658                         dma_addr =
+02659                             dwc_ep->dma_addr1 + dwc_ep->xfer_len -
+02660                             deptsiz.b.xfersize;
+02661                 } else {
+02662                         dma_addr =
+02663                             dwc_ep->dma_addr0 + dwc_ep->xfer_len -
+02664                             deptsiz.b.xfersize;;
+02665                 }
+02666 
+02667                 dwc_write_reg32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->
+02668                                 doepdma, dma_addr);
+02669 
+02671                 depctl.d32 = 0;
+02672                 depctl.b.epena = 1;
+02673                 depctl.b.cnak = 1;
+02674 
+02675                 dwc_modify_reg32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->
+02676                                  doepctl, depctl.d32, depctl.d32);
+02677                 return 0;
+02678         } else {
+02679                 return 1;
+02680         }
+02681 }
+02682 
+02690 static uint32_t set_iso_pkts_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep)
+02691 {
+02692         int i, j;
+02693         dma_addr_t dma_ad;
+02694         iso_pkt_info_t *packet_info = ep->pkt_info;
+02695         uint32_t offset;
+02696         uint32_t frame_data;
+02697         deptsiz_data_t deptsiz;
+02698 
+02699         if (ep->proc_buf_num == 0) {
+02701                 dma_ad = ep->dma_addr0;
+02702         } else {
+02704                 dma_ad = ep->dma_addr1;
+02705         }
+02706 
+02707         if (ep->is_in) {
+02708                 deptsiz.d32 =
+02709                     dwc_read_reg32(&core_if->dev_if->in_ep_regs[ep->num]->
+02710                                    dieptsiz);
+02711         } else {
+02712                 deptsiz.d32 =
+02713                     dwc_read_reg32(&core_if->dev_if->out_ep_regs[ep->num]->
+02714                                    doeptsiz);
+02715         }
+02716 
+02717         if (!deptsiz.b.xfersize) {
+02718                 offset = 0;
+02719                 for (i = 0; i < ep->pkt_cnt; i += ep->pkt_per_frm) {
+02720                         frame_data = ep->data_per_frame;
+02721                         for (j = 0; j < ep->pkt_per_frm; ++j) {
+02722 
+02723                                 /* Packet status - is not set as initially 
+02724                                  * it is set to 0 and if packet was sent 
+02725                                  successfully, status field will remain 0*/
+02726 
+02727                                 /* Bytes has been transfered */
+02728                                 packet_info->length =
+02729                                     (ep->maxpacket <
+02730                                      frame_data) ? ep->maxpacket : frame_data;
+02731 
+02732                                 /* Received packet offset */
+02733                                 packet_info->offset = offset;
+02734                                 offset += packet_info->length;
+02735                                 frame_data -= packet_info->length;
+02736 
+02737                                 packet_info++;
+02738                         }
+02739                 }
+02740                 return 1;
+02741         } else {
+02742                 /* This is a workaround for in case of Transfer Complete with 
+02743                  * PktDrpSts interrupts merging - in this case Transfer complete 
+02744                  * interrupt for Isoc Out Endpoint is asserted without PktDrpSts 
+02745                  * set and with DOEPTSIZ register non zero. Investigations showed,
+02746                  * that this happens when Out packet is dropped, but because of 
+02747                  * interrupts merging during first interrupt handling PktDrpSts
+02748                  * bit is cleared and for next merged interrupts it is not reset.
+02749                  * In this case SW hadles the interrupt as if PktDrpSts bit is set.
+02750                  */
+02751                 if (ep->is_in) {
+02752                         return 1;
+02753                 } else {
+02754                         return handle_iso_out_pkt_dropped(core_if, ep);
+02755                 }
+02756         }
+02757 }
+02758 
+02766 static void complete_iso_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep)
+02767 {
+02768         dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd);
+02769         dwc_ep_t *dwc_ep = &ep->dwc_ep;
+02770         uint8_t is_last = 0;
+02771 
+02772         if(ep->dwc_ep.next_frame == 0xffffffff) {
+02773                 DWC_WARN("Next frame is not set!\n");
+02774                 return;
+02775         }
+02776 
+02777         if (core_if->dma_enable) {
+02778                 if (core_if->dma_desc_enable) {
+02779                         set_ddma_iso_pkts_info(core_if, dwc_ep);
+02780                         reinit_ddma_iso_xfer(core_if, dwc_ep);
+02781                         is_last = 1;
+02782                 } else {
+02783                         if (core_if->pti_enh_enable) {
+02784                                 if (set_iso_pkts_info(core_if, dwc_ep)) {
+02785                                         dwc_ep->proc_buf_num =
+02786                                             (dwc_ep->proc_buf_num ^ 1) & 0x1;
+02787                                         dwc_otg_iso_ep_start_buf_transfer
+02788                                             (core_if, dwc_ep);
+02789                                         is_last = 1;
+02790                                 }
+02791                         } else {
+02792                                 set_current_pkt_info(core_if, dwc_ep);
+02793                                 if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
+02794                                         is_last = 1;
+02795                                         dwc_ep->cur_pkt = 0;
+02796                                         dwc_ep->proc_buf_num =
+02797                                             (dwc_ep->proc_buf_num ^ 1) & 0x1;
+02798                                         if (dwc_ep->proc_buf_num) {
+02799                                                 dwc_ep->cur_pkt_addr =
+02800                                                     dwc_ep->xfer_buff1;
+02801                                                 dwc_ep->cur_pkt_dma_addr =
+02802                                                     dwc_ep->dma_addr1;
+02803                                         } else {
+02804                                                 dwc_ep->cur_pkt_addr =
+02805                                                     dwc_ep->xfer_buff0;
+02806                                                 dwc_ep->cur_pkt_dma_addr =
+02807                                                     dwc_ep->dma_addr0;
+02808                                         }
+02809 
+02810                                 }
+02811                                 dwc_otg_iso_ep_start_frm_transfer(core_if,
+02812                                                                   dwc_ep);
+02813                         }
+02814                 }
+02815         } else {
+02816                 set_current_pkt_info(core_if, dwc_ep);
+02817                 if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
+02818                         is_last = 1;
+02819                         dwc_ep->cur_pkt = 0;
+02820                         dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1;
+02821                         if (dwc_ep->proc_buf_num) {
+02822                                 dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff1;
+02823                                 dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr1;
+02824                         } else {
+02825                                 dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff0;
+02826                                 dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr0;
+02827                         }
+02828 
+02829                 }
+02830                 dwc_otg_iso_ep_start_frm_transfer(core_if, dwc_ep);
+02831         }
+02832         if (is_last)
+02833                 dwc_otg_iso_buffer_done(pcd, ep, ep->iso_req_handle);
+02834 }
+02835 #endif                          /* DWC_EN_ISOC */
+02836 
+02843 static void handle_ep0(dwc_otg_pcd_t * pcd)
+02844 {
+02845         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+02846         dwc_otg_pcd_ep_t *ep0 = &pcd->ep0;
+02847         dev_dma_desc_sts_t desc_sts;
+02848         deptsiz0_data_t deptsiz;
+02849         uint32_t byte_count;
+02850 
+02851 #ifdef DEBUG_EP0
+02852         DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
+02853         print_ep0_state(pcd);
+02854 #endif
+02855 
+02856 //      DWC_PRINTF("HANDLE EP0\n");
+02857 
+02858         switch (pcd->ep0state) {
+02859         case EP0_DISCONNECT:
+02860                 break;
+02861 
+02862         case EP0_IDLE:
+02863                 pcd->request_config = 0;
+02864 
+02865                 pcd_setup(pcd);
+02866                 break;
+02867 
+02868         case EP0_IN_DATA_PHASE:
+02869 #ifdef DEBUG_EP0
+02870                 DWC_DEBUGPL(DBG_PCD, "DATA_IN EP%d-%s: type=%d, mps=%d\n",
+02871                             ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
+02872                             ep0->dwc_ep.type, ep0->dwc_ep.maxpacket);
+02873 #endif
+02874 
+02875                 if (core_if->dma_enable != 0) {
+02876                         /*
+02877                          * For EP0 we can only program 1 packet at a time so we
+02878                          * need to do the make calculations after each complete.
+02879                          * Call write_packet to make the calculations, as in
+02880                          * slave mode, and use those values to determine if we
+02881                          * can complete.
+02882                          */
+02883                         if (core_if->dma_desc_enable == 0) {
+02884                                 deptsiz.d32 =
+02885                                     dwc_read_reg32(&core_if->dev_if->
+02886                                                    in_ep_regs[0]->dieptsiz);
+02887                                 byte_count =
+02888                                     ep0->dwc_ep.xfer_len - deptsiz.b.xfersize;
+02889                         } else {
+02890                                 desc_sts =
+02891                                     core_if->dev_if->in_desc_addr->status;
+02892                                 byte_count =
+02893                                     ep0->dwc_ep.xfer_len - desc_sts.b.bytes;
+02894                         }
+02895                         ep0->dwc_ep.xfer_count += byte_count;
+02896                         ep0->dwc_ep.xfer_buff += byte_count;
+02897                         ep0->dwc_ep.dma_addr += byte_count;
+02898                 }
+02899                 if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) {
+02900                         dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
+02901                                                       &ep0->dwc_ep);
+02902                         DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
+02903                 } else if (ep0->dwc_ep.sent_zlp) {
+02904                         dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
+02905                                                       &ep0->dwc_ep);
+02906                         ep0->dwc_ep.sent_zlp = 0;
+02907                         DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
+02908                 } else {
+02909                         ep0_complete_request(ep0);
+02910                         DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
+02911                 }
+02912                 break;
+02913         case EP0_OUT_DATA_PHASE:
+02914 #ifdef DEBUG_EP0
+02915                 DWC_DEBUGPL(DBG_PCD, "DATA_OUT EP%d-%s: type=%d, mps=%d\n",
+02916                             ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"),
+02917                             ep0->dwc_ep.type, ep0->dwc_ep.maxpacket);
+02918 #endif
+02919                 if (core_if->dma_enable != 0) {
+02920                         if (core_if->dma_desc_enable == 0) {
+02921                                 deptsiz.d32 =
+02922                                     dwc_read_reg32(&core_if->dev_if->
+02923                                                    out_ep_regs[0]->doeptsiz);
+02924                                 byte_count =
+02925                                     ep0->dwc_ep.maxpacket - deptsiz.b.xfersize;
+02926                         } else {
+02927                                 desc_sts =
+02928                                     core_if->dev_if->out_desc_addr->status;
+02929                                 byte_count =
+02930                                     ep0->dwc_ep.maxpacket - desc_sts.b.bytes;
+02931                         }
+02932                         ep0->dwc_ep.xfer_count += byte_count;
+02933                         ep0->dwc_ep.xfer_buff += byte_count;
+02934                         ep0->dwc_ep.dma_addr += byte_count;
+02935                 }
+02936                 if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) {
+02937                         dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
+02938                                                       &ep0->dwc_ep);
+02939                         DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
+02940                 } else if (ep0->dwc_ep.sent_zlp) {
+02941                         dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd),
+02942                                                       &ep0->dwc_ep);
+02943                         ep0->dwc_ep.sent_zlp = 0;
+02944                         DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n");
+02945                 } else {
+02946                         ep0_complete_request(ep0);
+02947                         DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n");
+02948                 }
+02949                 break;
+02950 
+02951         case EP0_IN_STATUS_PHASE:
+02952         case EP0_OUT_STATUS_PHASE:
+02953                 DWC_DEBUGPL(DBG_PCD, "CASE: EP0_STATUS\n");
+02954                 ep0_complete_request(ep0);
+02955                 pcd->ep0state = EP0_IDLE;
+02956                 ep0->stopped = 1;
+02957                 ep0->dwc_ep.is_in = 0;  /* OUT for next SETUP */
+02958 
+02959                 /* Prepare for more SETUP Packets */
+02960                 if (core_if->dma_enable) {
+02961                         ep0_out_start(core_if, pcd);
+02962                 }
+02963                 break;
+02964 
+02965         case EP0_STALL:
+02966                 DWC_ERROR("EP0 STALLed, should not get here pcd_setup()\n");
+02967                 break;
+02968         }
+02969 #ifdef DEBUG_EP0
+02970         print_ep0_state(pcd);
+02971 #endif
+02972 }
+02973 
+02977 static void restart_transfer(dwc_otg_pcd_t * pcd, const uint32_t epnum)
+02978 {
+02979         dwc_otg_core_if_t *core_if;
+02980         dwc_otg_dev_if_t *dev_if;
+02981         deptsiz_data_t dieptsiz = {.d32 = 0 };
+02982         dwc_otg_pcd_ep_t *ep;
+02983 
+02984         ep = get_in_ep(pcd, epnum);
+02985 
+02986 #ifdef DWC_EN_ISOC
+02987         if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
+02988                 return;
+02989         }
+02990 #endif                          /* DWC_EN_ISOC  */
+02991 
+02992         core_if = GET_CORE_IF(pcd);
+02993         dev_if = core_if->dev_if;
+02994 
+02995         dieptsiz.d32 = dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dieptsiz);
+02996 
+02997         DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x xfer_len=%0x"
+02998                     " stopped=%d\n", ep->dwc_ep.xfer_buff,
+02999                     ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len, ep->stopped);
+03000         /*
+03001          * If xfersize is 0 and pktcnt in not 0, resend the last packet.
+03002          */
+03003         if (dieptsiz.b.pktcnt && dieptsiz.b.xfersize == 0 &&
+03004             ep->dwc_ep.start_xfer_buff != 0) {
+03005                 if (ep->dwc_ep.total_len <= ep->dwc_ep.maxpacket) {
+03006                         ep->dwc_ep.xfer_count = 0;
+03007                         ep->dwc_ep.xfer_buff = ep->dwc_ep.start_xfer_buff;
+03008                         ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count;
+03009                 } else {
+03010                         ep->dwc_ep.xfer_count -= ep->dwc_ep.maxpacket;
+03011                         /* convert packet size to dwords. */
+03012                         ep->dwc_ep.xfer_buff -= ep->dwc_ep.maxpacket;
+03013                         ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count;
+03014                 }
+03015                 ep->stopped = 0;
+03016                 DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x "
+03017                             "xfer_len=%0x stopped=%d\n",
+03018                             ep->dwc_ep.xfer_buff,
+03019                             ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len,
+03020                             ep->stopped);
+03021                 if (epnum == 0) {
+03022                         dwc_otg_ep0_start_transfer(core_if, &ep->dwc_ep);
+03023                 } else {
+03024                         dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep);
+03025                 }
+03026         }
+03027 }
+03028 
+03032 static inline void handle_in_ep_disable_intr(dwc_otg_pcd_t * pcd,
+03033                                              const uint32_t epnum)
+03034 {
+03035         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+03036         dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+03037         deptsiz_data_t dieptsiz = {.d32 = 0 };
+03038         dctl_data_t dctl = {.d32 = 0 };
+03039         dwc_otg_pcd_ep_t *ep;
+03040         dwc_ep_t *dwc_ep;
+03041 
+03042         ep = get_in_ep(pcd, epnum);
+03043         dwc_ep = &ep->dwc_ep;
+03044 
+03045         if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
+03046                 dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num);
+03047                 return;
+03048         }
+03049 
+03050         DWC_DEBUGPL(DBG_PCD, "diepctl%d=%0x\n", epnum,
+03051                     dwc_read_reg32(&dev_if->in_ep_regs[epnum]->diepctl));
+03052         dieptsiz.d32 = dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dieptsiz);
+03053 
+03054         DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
+03055                     dieptsiz.b.pktcnt, dieptsiz.b.xfersize);
+03056 
+03057         if (ep->stopped) {
+03058                 /* Flush the Tx FIFO */
+03059                 dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num);
+03060                 /* Clear the Global IN NP NAK */
+03061                 dctl.d32 = 0;
+03062                 dctl.b.cgnpinnak = 1;
+03063                 dwc_modify_reg32(&dev_if->dev_global_regs->dctl, dctl.d32, 0);
+03064                 /* Restart the transaction */
+03065                 if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) {
+03066                         restart_transfer(pcd, epnum);
+03067                 }
+03068         } else {
+03069                 /* Restart the transaction */
+03070                 if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) {
+03071                         restart_transfer(pcd, epnum);
+03072                 }
+03073                 DWC_DEBUGPL(DBG_ANY, "STOPPED!!!\n");
+03074         }
+03075 }
+03076 
+03080 static inline void handle_in_ep_timeout_intr(dwc_otg_pcd_t * pcd,
+03081                                              const uint32_t epnum)
+03082 {
+03083         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+03084         dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+03085 
+03086 #ifdef DEBUG
+03087         deptsiz_data_t dieptsiz = {.d32 = 0 };
+03088         uint32_t num = 0;
+03089 #endif
+03090         dctl_data_t dctl = {.d32 = 0 };
+03091         dwc_otg_pcd_ep_t *ep;
+03092 
+03093         gintmsk_data_t intr_mask = {.d32 = 0 };
+03094 
+03095         ep = get_in_ep(pcd, epnum);
+03096 
+03097         /* Disable the NP Tx Fifo Empty Interrrupt */
+03098         if (!core_if->dma_enable) {
+03099                 intr_mask.b.nptxfempty = 1;
+03100                 dwc_modify_reg32(&core_if->core_global_regs->gintmsk,
+03101                                  intr_mask.d32, 0);
+03102         }
+03105         /*
+03106          * Non-periodic EP
+03107          */
+03108         /* Enable the Global IN NAK Effective Interrupt */
+03109         intr_mask.b.ginnakeff = 1;
+03110         dwc_modify_reg32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32);
+03111 
+03112         /* Set Global IN NAK */
+03113         dctl.b.sgnpinnak = 1;
+03114         dwc_modify_reg32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
+03115 
+03116         ep->stopped = 1;
+03117 
+03118 #ifdef DEBUG
+03119         dieptsiz.d32 = dwc_read_reg32(&dev_if->in_ep_regs[num]->dieptsiz);
+03120         DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n",
+03121                     dieptsiz.b.pktcnt, dieptsiz.b.xfersize);
+03122 #endif
+03123 
+03124 #ifdef DISABLE_PERIODIC_EP
+03125         /*
+03126          * Set the NAK bit for this EP to
+03127          * start the disable process.
+03128          */
+03129         diepctl.d32 = 0;
+03130         diepctl.b.snak = 1;
+03131         dwc_modify_reg32(&dev_if->in_ep_regs[num]->diepctl, diepctl.d32,
+03132                          diepctl.d32);
+03133         ep->disabling = 1;
+03134         ep->stopped = 1;
+03135 #endif
+03136 }
+03137 
+03141 static inline int32_t handle_in_ep_nak_intr(dwc_otg_pcd_t * pcd,
+03142                                             const uint32_t epnum)
+03143 {
+03145         dwc_otg_core_if_t *core_if;
+03146         diepmsk_data_t intr_mask = {.d32 = 0 };
+03147 
+03148         DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "IN EP NAK");
+03149         core_if = GET_CORE_IF(pcd);
+03150         intr_mask.b.nak = 1;
+03151 
+03152         if (core_if->multiproc_int_enable) {
+03153                 dwc_modify_reg32(&core_if->dev_if->dev_global_regs->
+03154                                  diepeachintmsk[epnum], intr_mask.d32, 0);
+03155         } else {
+03156                 dwc_modify_reg32(&core_if->dev_if->dev_global_regs->diepmsk,
+03157                                  intr_mask.d32, 0);
+03158         }
+03159 
+03160         return 1;
+03161 }
+03162 
+03166 static inline int32_t handle_out_ep_babble_intr(dwc_otg_pcd_t * pcd,
+03167                                                 const uint32_t epnum)
+03168 {
+03170         dwc_otg_core_if_t *core_if;
+03171         doepmsk_data_t intr_mask = {.d32 = 0 };
+03172 
+03173         DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
+03174                    "OUT EP Babble");
+03175         core_if = GET_CORE_IF(pcd);
+03176         intr_mask.b.babble = 1;
+03177 
+03178         if (core_if->multiproc_int_enable) {
+03179                 dwc_modify_reg32(&core_if->dev_if->dev_global_regs->
+03180                                  doepeachintmsk[epnum], intr_mask.d32, 0);
+03181         } else {
+03182                 dwc_modify_reg32(&core_if->dev_if->dev_global_regs->doepmsk,
+03183                                  intr_mask.d32, 0);
+03184         }
+03185 
+03186         return 1;
+03187 }
+03188 
+03192 static inline int32_t handle_out_ep_nak_intr(dwc_otg_pcd_t * pcd,
+03193                                              const uint32_t epnum)
+03194 {
+03196         dwc_otg_core_if_t *core_if;
+03197         doepmsk_data_t intr_mask = {.d32 = 0 };
+03198 
+03199         DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "OUT EP NAK");
+03200         core_if = GET_CORE_IF(pcd);
+03201         intr_mask.b.nak = 1;
+03202 
+03203         if (core_if->multiproc_int_enable) {
+03204                 dwc_modify_reg32(&core_if->dev_if->dev_global_regs->
+03205                                  doepeachintmsk[epnum], intr_mask.d32, 0);
+03206         } else {
+03207                 dwc_modify_reg32(&core_if->dev_if->dev_global_regs->doepmsk,
+03208                                  intr_mask.d32, 0);
+03209         }
+03210 
+03211         return 1;
+03212 }
+03213 
+03217 static inline int32_t handle_out_ep_nyet_intr(dwc_otg_pcd_t * pcd,
+03218                                               const uint32_t epnum)
+03219 {
+03221         dwc_otg_core_if_t *core_if;
+03222         doepmsk_data_t intr_mask = {.d32 = 0 };
+03223 
+03224         DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "OUT EP NYET");
+03225         core_if = GET_CORE_IF(pcd);
+03226         intr_mask.b.nyet = 1;
+03227 
+03228         if (core_if->multiproc_int_enable) {
+03229                 dwc_modify_reg32(&core_if->dev_if->dev_global_regs->
+03230                                  doepeachintmsk[epnum], intr_mask.d32, 0);
+03231         } else {
+03232                 dwc_modify_reg32(&core_if->dev_if->dev_global_regs->doepmsk,
+03233                                  intr_mask.d32, 0);
+03234         }
+03235 
+03236         return 1;
+03237 }
+03238 
+03255 static int32_t dwc_otg_pcd_handle_in_ep_intr(dwc_otg_pcd_t * pcd)
+03256 {
+03257 #define CLEAR_IN_EP_INTR(__core_if,__epnum,__intr) \
+03258 do { \
+03259                 diepint_data_t diepint = {.d32=0}; \
+03260                 diepint.b.__intr = 1; \
+03261                 dwc_write_reg32(&__core_if->dev_if->in_ep_regs[__epnum]->diepint, \
+03262                 diepint.d32); \
+03263 } while (0)
+03264 
+03265         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+03266         dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+03267         diepint_data_t diepint = {.d32 = 0 };
+03268         dctl_data_t dctl = {.d32 = 0 };
+03269         depctl_data_t depctl = {.d32 = 0 };
+03270         uint32_t ep_intr;
+03271         uint32_t epnum = 0;
+03272         dwc_otg_pcd_ep_t *ep;
+03273         dwc_ep_t *dwc_ep;
+03274         gintmsk_data_t intr_mask = {.d32 = 0 };
+03275 
+03276         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, pcd);
+03277 
+03278         /* Read in the device interrupt bits */
+03279         ep_intr = dwc_otg_read_dev_all_in_ep_intr(core_if);
+03280 
+03281         /* Service the Device IN interrupts for each endpoint */
+03282         while (ep_intr) {
+03283                 if (ep_intr & 0x1) {
+03284                         uint32_t empty_msk;
+03285                         /* Get EP pointer */
+03286                         ep = get_in_ep(pcd, epnum);
+03287                         dwc_ep = &ep->dwc_ep;
+03288 
+03289                         depctl.d32 =
+03290                             dwc_read_reg32(&dev_if->in_ep_regs[epnum]->diepctl);
+03291                         empty_msk =
+03292                             dwc_read_reg32(&dev_if->dev_global_regs->
+03293                                            dtknqr4_fifoemptymsk);
+03294 
+03295                         DWC_DEBUGPL(DBG_PCDV,
+03296                                     "IN EP INTERRUPT - %d\nepmty_msk - %8x  diepctl - %8x\n",
+03297                                     epnum, empty_msk, depctl.d32);
+03298 
+03299                         DWC_DEBUGPL(DBG_PCD,
+03300                                     "EP%d-%s: type=%d, mps=%d\n",
+03301                                     dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"),
+03302                                     dwc_ep->type, dwc_ep->maxpacket);
+03303 
+03304                         diepint.d32 =
+03305                             dwc_otg_read_dev_in_ep_intr(core_if, dwc_ep);
+03306 
+03307                         DWC_DEBUGPL(DBG_PCDV,
+03308                                     "EP %d Interrupt Register - 0x%x\n", epnum,
+03309                                     diepint.d32);
+03310                         /* Transfer complete */
+03311                         if (diepint.b.xfercompl) {
+03312                                 /* Disable the NP Tx FIFO Empty
+03313                                  * Interrrupt */
+03314                                 if (core_if->en_multiple_tx_fifo == 0) {
+03315                                         intr_mask.b.nptxfempty = 1;
+03316                                         dwc_modify_reg32(&core_if->
+03317                                                          core_global_regs->
+03318                                                          gintmsk, intr_mask.d32,
+03319                                                          0);
+03320                                 } else {
+03321                                         /* Disable the Tx FIFO Empty Interrupt for this EP */
+03322                                         uint32_t fifoemptymsk =
+03323                                             0x1 << dwc_ep->num;
+03324                                         dwc_modify_reg32(&core_if->dev_if->
+03325                                                          dev_global_regs->
+03326                                                          dtknqr4_fifoemptymsk,
+03327                                                          fifoemptymsk, 0);
+03328                                 }
+03329                                 /* Clear the bit in DIEPINTn for this interrupt */
+03330                                 CLEAR_IN_EP_INTR(core_if, epnum, xfercompl);
+03331 
+03332                                 /* Complete the transfer */
+03333                                 if (epnum == 0) {
+03334                                         handle_ep0(pcd);
+03335                                 }
+03336 #ifdef DWC_EN_ISOC
+03337                                 else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
+03338                                         if (!ep->stopped)
+03339                                                 complete_iso_ep(pcd, ep);
+03340                                 }
+03341 #endif                          /* DWC_EN_ISOC */
+03342                                 else {
+03343 
+03344                                         complete_ep(ep);
+03345                                 }
+03346                         }
+03347                         /* Endpoint disable      */
+03348                         if (diepint.b.epdisabled) {
+03349                                 DWC_DEBUGPL(DBG_ANY, "EP%d IN disabled\n",
+03350                                             epnum);
+03351                                 handle_in_ep_disable_intr(pcd, epnum);
+03352 
+03353                                 /* Clear the bit in DIEPINTn for this interrupt */
+03354                                 CLEAR_IN_EP_INTR(core_if, epnum, epdisabled);
+03355                         }
+03356                         /* AHB Error */
+03357                         if (diepint.b.ahberr) {
+03358                                 DWC_DEBUGPL(DBG_ANY, "EP%d IN AHB Error\n",
+03359                                             epnum);
+03360                                 /* Clear the bit in DIEPINTn for this interrupt */
+03361                                 CLEAR_IN_EP_INTR(core_if, epnum, ahberr);
+03362                         }
+03363                         /* TimeOUT Handshake (non-ISOC IN EPs) */
+03364                         if (diepint.b.timeout) {
+03365                                 DWC_DEBUGPL(DBG_ANY, "EP%d IN Time-out\n",
+03366                                             epnum);
+03367                                 handle_in_ep_timeout_intr(pcd, epnum);
+03368 
+03369                                 CLEAR_IN_EP_INTR(core_if, epnum, timeout);
+03370                         }
+03372                         if (diepint.b.intktxfemp) {
+03373                                 DWC_DEBUGPL(DBG_ANY,
+03374                                             "EP%d IN TKN TxFifo Empty\n",
+03375                                             epnum);
+03376                                 if (!ep->stopped && epnum != 0) {
+03377 
+03378                                         diepmsk_data_t diepmsk = {.d32 = 0 };
+03379                                         diepmsk.b.intktxfemp = 1;
+03380 
+03381                                         if (core_if->multiproc_int_enable) {
+03382                                                 dwc_modify_reg32(&dev_if->
+03383                                                                  dev_global_regs->
+03384                                                                  diepeachintmsk
+03385                                                                  [epnum],
+03386                                                                  diepmsk.d32,
+03387                                                                  0);
+03388                                         } else {
+03389                                                 dwc_modify_reg32(&dev_if->
+03390                                                                  dev_global_regs->
+03391                                                                  diepmsk,
+03392                                                                  diepmsk.d32,
+03393                                                                  0);
+03394                                         }
+03395                                 } else if (core_if->dma_desc_enable
+03396                                            && epnum == 0
+03397                                            && pcd->ep0state ==
+03398                                            EP0_OUT_STATUS_PHASE) {
+03399                                         // EP0 IN set STALL
+03400                                         depctl.d32 =
+03401                                             dwc_read_reg32(&dev_if->
+03402                                                            in_ep_regs[epnum]->
+03403                                                            diepctl);
+03404 
+03405                                         /* set the disable and stall bits */
+03406                                         if (depctl.b.epena) {
+03407                                                 depctl.b.epdis = 1;
+03408                                         }
+03409                                         depctl.b.stall = 1;
+03410                                         dwc_write_reg32(&dev_if->
+03411                                                         in_ep_regs[epnum]->
+03412                                                         diepctl, depctl.d32);
+03413                                 }
+03414                                 CLEAR_IN_EP_INTR(core_if, epnum, intktxfemp);
+03415                         }
+03417                         if (diepint.b.intknepmis) {
+03418                                 DWC_DEBUGPL(DBG_ANY,
+03419                                             "EP%d IN TKN EP Mismatch\n", epnum);
+03420                                 CLEAR_IN_EP_INTR(core_if, epnum, intknepmis);
+03421                         }
+03423                         if (diepint.b.inepnakeff) {
+03424                                 DWC_DEBUGPL(DBG_ANY,
+03425                                             "EP%d IN EP NAK Effective\n",
+03426                                             epnum);
+03427                                 /* Periodic EP */
+03428                                 if (ep->disabling) {
+03429                                         depctl.d32 = 0;
+03430                                         depctl.b.snak = 1;
+03431                                         depctl.b.epdis = 1;
+03432                                         dwc_modify_reg32(&dev_if->
+03433                                                          in_ep_regs[epnum]->
+03434                                                          diepctl, depctl.d32,
+03435                                                          depctl.d32);
+03436                                 }
+03437                                 CLEAR_IN_EP_INTR(core_if, epnum, inepnakeff);
+03438 
+03439                         }
+03440 
+03442                         if (diepint.b.emptyintr) {
+03443                                 DWC_DEBUGPL(DBG_ANY,
+03444                                             "EP%d Tx FIFO Empty Intr \n",
+03445                                             epnum);
+03446                                 write_empty_tx_fifo(pcd, epnum);
+03447 
+03448                                 CLEAR_IN_EP_INTR(core_if, epnum, emptyintr);
+03449 
+03450                         }
+03451 
+03453                         if (diepint.b.bna) {
+03454                                 CLEAR_IN_EP_INTR(core_if, epnum, bna);
+03455                                 if (core_if->dma_desc_enable) {
+03456 #ifdef DWC_EN_ISOC
+03457                                         if (dwc_ep->type ==
+03458                                             DWC_OTG_EP_TYPE_ISOC) {
+03459                                                 /*
+03460                                                  * This checking is performed to prevent first "false" BNA 
+03461                                                  * handling occuring right after reconnect 
+03462                                                  */
+03463                                                 if (dwc_ep->next_frame !=
+03464                                                     0xffffffff)
+03465                                                         dwc_otg_pcd_handle_iso_bna
+03466                                                             (ep);
+03467                                         } else
+03468 #endif                          /* DWC_EN_ISOC */
+03469                                         {
+03470                                                 dctl.d32 =
+03471                                                     dwc_read_reg32(&dev_if->
+03472                                                                    dev_global_regs->
+03473                                                                    dctl);
+03474 
+03475                                                 /* If Global Continue on BNA is disabled - disable EP */
+03476                                                 if (!dctl.b.gcontbna) {
+03477                                                         depctl.d32 = 0;
+03478                                                         depctl.b.snak = 1;
+03479                                                         depctl.b.epdis = 1;
+03480                                                         dwc_modify_reg32
+03481                                                             (&dev_if->
+03482                                                              in_ep_regs[epnum]->
+03483                                                              diepctl,
+03484                                                              depctl.d32,
+03485                                                              depctl.d32);
+03486                                                 } else {
+03487                                                         start_next_request(ep);
+03488                                                 }
+03489                                         }
+03490                                 }
+03491                         }
+03492                         /* NAK Interrutp */
+03493                         if (diepint.b.nak) {
+03494                                 DWC_DEBUGPL(DBG_ANY, "EP%d IN NAK Interrupt\n",
+03495                                             epnum);
+03496                                 handle_in_ep_nak_intr(pcd, epnum);
+03497 
+03498                                 CLEAR_IN_EP_INTR(core_if, epnum, nak);
+03499                         }
+03500                 }
+03501                 epnum++;
+03502                 ep_intr >>= 1;
+03503         }
+03504 
+03505         return 1;
+03506 #undef CLEAR_IN_EP_INTR
+03507 }
+03508 
+03522 static int32_t dwc_otg_pcd_handle_out_ep_intr(dwc_otg_pcd_t * pcd)
+03523 {
+03524 #define CLEAR_OUT_EP_INTR(__core_if,__epnum,__intr) \
+03525 do { \
+03526                 doepint_data_t doepint = {.d32=0}; \
+03527                 doepint.b.__intr = 1; \
+03528                 dwc_write_reg32(&__core_if->dev_if->out_ep_regs[__epnum]->doepint, \
+03529                 doepint.d32); \
+03530 } while (0)
+03531 
+03532         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+03533         dwc_otg_dev_if_t *dev_if = core_if->dev_if;
+03534         uint32_t ep_intr;
+03535         doepint_data_t doepint = {.d32 = 0 };
+03536         dctl_data_t dctl = {.d32 = 0 };
+03537         depctl_data_t doepctl = {.d32 = 0 };
+03538         uint32_t epnum = 0;
+03539         dwc_otg_pcd_ep_t *ep;
+03540         dwc_ep_t *dwc_ep;
+03541 
+03542         DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__);
+03543 
+03544         /* Read in the device interrupt bits */
+03545         ep_intr = dwc_otg_read_dev_all_out_ep_intr(core_if);
+03546 
+03547         while (ep_intr) {
+03548                 if (ep_intr & 0x1) {
+03549                         /* Get EP pointer */
+03550                         ep = get_out_ep(pcd, epnum);
+03551                         dwc_ep = &ep->dwc_ep;
+03552 
+03553 #ifdef VERBOSE
+03554                         DWC_DEBUGPL(DBG_PCDV,
+03555                                     "EP%d-%s: type=%d, mps=%d\n",
+03556                                     dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"),
+03557                                     dwc_ep->type, dwc_ep->maxpacket);
+03558 #endif
+03559                         doepint.d32 =
+03560                             dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep);
+03561 
+03562                         /* Transfer complete */
+03563                         if (doepint.b.xfercompl) {
+03564 
+03565                                 if (epnum == 0) {
+03566                                         /* Clear the bit in DOEPINTn for this interrupt */
+03567                                         CLEAR_OUT_EP_INTR(core_if, epnum,
+03568                                                           xfercompl);
+03569                                         if (core_if->dma_desc_enable == 0
+03570                                             || pcd->ep0state != EP0_IDLE)
+03571                                                 handle_ep0(pcd);
+03572 #ifdef DWC_EN_ISOC
+03573                                 } else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
+03574                                         if (doepint.b.pktdrpsts == 0) {
+03575                                                 /* Clear the bit in DOEPINTn for this interrupt */
+03576                                                 CLEAR_OUT_EP_INTR(core_if,
+03577                                                                   epnum,
+03578                                                                   xfercompl);
+03579                                                 complete_iso_ep(pcd, ep);
+03580                                         } else {
+03581 
+03582                                                 doepint_data_t doepint = {.d32 =
+03583                                                             0 };
+03584                                                 doepint.b.xfercompl = 1;
+03585                                                 doepint.b.pktdrpsts = 1;
+03586                                                 dwc_write_reg32(&core_if->
+03587                                                                 dev_if->
+03588                                                                 out_ep_regs
+03589                                                                 [epnum]->
+03590                                                                 doepint,
+03591                                                                 doepint.d32);
+03592                                                 if (handle_iso_out_pkt_dropped
+03593                                                     (core_if, dwc_ep)) {
+03594                                                         complete_iso_ep(pcd,
+03595                                                                         ep);
+03596                                                 }
+03597                                         }
+03598 #endif                          /* DWC_EN_ISOC */
+03599                                 } else {
+03600                                         /* Clear the bit in DOEPINTn for this interrupt */
+03601                                         CLEAR_OUT_EP_INTR(core_if, epnum,
+03602                                                           xfercompl);
+03603                                         complete_ep(ep);
+03604                                 }
+03605 
+03606                         }
+03607 
+03608                         /* Endpoint disable      */
+03609                         if (doepint.b.epdisabled) {
+03610 
+03611                                 /* Clear the bit in DOEPINTn for this interrupt */
+03612                                 CLEAR_OUT_EP_INTR(core_if, epnum, epdisabled);
+03613                         }
+03614                         /* AHB Error */
+03615                         if (doepint.b.ahberr) {
+03616                                 DWC_DEBUGPL(DBG_PCD, "EP%d OUT AHB Error\n",
+03617                                             epnum);
+03618                                 DWC_DEBUGPL(DBG_PCD, "EP DMA REG         %d \n",
+03619                                             core_if->dev_if->
+03620                                             out_ep_regs[epnum]->doepdma);
+03621                                 CLEAR_OUT_EP_INTR(core_if, epnum, ahberr);
+03622                         }
+03623                         /* Setup Phase Done (contorl EPs) */
+03624                         if (doepint.b.setup) {
+03625 #ifdef DEBUG_EP0
+03626                                 DWC_DEBUGPL(DBG_PCD, "EP%d SETUP Done\n",
+03627                                             epnum);
+03628 #endif
+03629                                 CLEAR_OUT_EP_INTR(core_if, epnum, setup);
+03630 
+03631                                 handle_ep0(pcd);
+03632                         }
+03633 
+03635                         if (doepint.b.bna) {
+03636                                 CLEAR_OUT_EP_INTR(core_if, epnum, bna);
+03637                                 if (core_if->dma_desc_enable) {
+03638 #ifdef DWC_EN_ISOC
+03639                                         if (dwc_ep->type ==
+03640                                             DWC_OTG_EP_TYPE_ISOC) {
+03641                                                 /*
+03642                                                  * This checking is performed to prevent first "false" BNA 
+03643                                                  * handling occuring right after reconnect 
+03644                                                  */
+03645                                                 if (dwc_ep->next_frame !=
+03646                                                     0xffffffff)
+03647                                                         dwc_otg_pcd_handle_iso_bna
+03648                                                             (ep);
+03649                                         } else
+03650 #endif                          /* DWC_EN_ISOC */
+03651                                         {
+03652                                                 dctl.d32 =
+03653                                                     dwc_read_reg32(&dev_if->
+03654                                                                    dev_global_regs->
+03655                                                                    dctl);
+03656 
+03657                                                 /* If Global Continue on BNA is disabled - disable EP */
+03658                                                 if (!dctl.b.gcontbna) {
+03659                                                         doepctl.d32 = 0;
+03660                                                         doepctl.b.snak = 1;
+03661                                                         doepctl.b.epdis = 1;
+03662                                                         dwc_modify_reg32
+03663                                                             (&dev_if->
+03664                                                              out_ep_regs
+03665                                                              [epnum]->doepctl,
+03666                                                              doepctl.d32,
+03667                                                              doepctl.d32);
+03668                                                 } else {
+03669                                                         start_next_request(ep);
+03670                                                 }
+03671                                         }
+03672                                 }
+03673                         }
+03674                         if (doepint.b.stsphsercvd) {
+03675                                 CLEAR_OUT_EP_INTR(core_if, epnum, stsphsercvd);
+03676                                 if (core_if->dma_desc_enable) {
+03677                                         do_setup_in_status_phase(pcd);
+03678                                 }
+03679                         }
+03680                         /* Babble Interrutp */
+03681                         if (doepint.b.babble) {
+03682                                 DWC_DEBUGPL(DBG_ANY, "EP%d OUT Babble\n",
+03683                                             epnum);
+03684                                 handle_out_ep_babble_intr(pcd, epnum);
+03685 
+03686                                 CLEAR_OUT_EP_INTR(core_if, epnum, babble);
+03687                         }
+03688                         /* NAK Interrutp */
+03689                         if (doepint.b.nak) {
+03690                                 DWC_DEBUGPL(DBG_ANY, "EP%d OUT NAK\n", epnum);
+03691                                 handle_out_ep_nak_intr(pcd, epnum);
+03692 
+03693                                 CLEAR_OUT_EP_INTR(core_if, epnum, nak);
+03694                         }
+03695                         /* NYET Interrutp */
+03696                         if (doepint.b.nyet) {
+03697                                 DWC_DEBUGPL(DBG_ANY, "EP%d OUT NYET\n", epnum);
+03698                                 handle_out_ep_nyet_intr(pcd, epnum);
+03699 
+03700                                 CLEAR_OUT_EP_INTR(core_if, epnum, nyet);
+03701                         }
+03702                 }
+03703 
+03704                 epnum++;
+03705                 ep_intr >>= 1;
+03706         }
+03707 
+03708         return 1;
+03709 
+03710 #undef CLEAR_OUT_EP_INTR
+03711 }
+03712 
+03725 int32_t dwc_otg_pcd_handle_incomplete_isoc_in_intr(dwc_otg_pcd_t * pcd)
+03726 {
+03727         gintsts_data_t gintsts;
+03728 
+03729 #ifdef DWC_EN_ISOC
+03730         dwc_otg_dev_if_t *dev_if;
+03731         deptsiz_data_t deptsiz = {.d32 = 0 };
+03732         depctl_data_t depctl = {.d32 = 0 };
+03733         dsts_data_t dsts = {.d32 = 0 };
+03734         dwc_ep_t *dwc_ep;
+03735         int i;
+03736 
+03737         dev_if = GET_CORE_IF(pcd)->dev_if;
+03738 
+03739         for (i = 1; i <= dev_if->num_in_eps; ++i) {
+03740                 dwc_ep = &pcd->in_ep[i].dwc_ep;
+03741                 if (dwc_ep->active && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) {
+03742                         deptsiz.d32 =
+03743                             dwc_read_reg32(&dev_if->in_ep_regs[i]->dieptsiz);
+03744                         depctl.d32 =
+03745                             dwc_read_reg32(&dev_if->in_ep_regs[i]->diepctl);
+03746 
+03747                         if (depctl.b.epdis && deptsiz.d32) {
+03748                                 set_current_pkt_info(GET_CORE_IF(pcd), dwc_ep);
+03749                                 if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
+03750                                         dwc_ep->cur_pkt = 0;
+03751                                         dwc_ep->proc_buf_num =
+03752                                             (dwc_ep->proc_buf_num ^ 1) & 0x1;
+03753 
+03754                                         if (dwc_ep->proc_buf_num) {
+03755                                                 dwc_ep->cur_pkt_addr =
+03756                                                     dwc_ep->xfer_buff1;
+03757                                                 dwc_ep->cur_pkt_dma_addr =
+03758                                                     dwc_ep->dma_addr1;
+03759                                         } else {
+03760                                                 dwc_ep->cur_pkt_addr =
+03761                                                     dwc_ep->xfer_buff0;
+03762                                                 dwc_ep->cur_pkt_dma_addr =
+03763                                                     dwc_ep->dma_addr0;
+03764                                         }
+03765 
+03766                                 }
+03767 
+03768                                 dsts.d32 =
+03769                                     dwc_read_reg32(&GET_CORE_IF(pcd)->dev_if->
+03770                                                    dev_global_regs->dsts);
+03771                                 dwc_ep->next_frame = dsts.b.soffn;
+03772 
+03773                                 dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF
+03774                                                                   (pcd),
+03775                                                                   dwc_ep);
+03776                         }
+03777                 }
+03778         }
+03779 
+03780 #else
+03781         gintmsk_data_t intr_mask = {.d32 = 0 };
+03782         DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
+03783                    "IN ISOC Incomplete");
+03784 
+03785         intr_mask.b.incomplisoin = 1;
+03786         dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
+03787                          intr_mask.d32, 0);
+03788 #endif                          //DWC_EN_ISOC
+03789 
+03790         /* Clear interrupt */
+03791         gintsts.d32 = 0;
+03792         gintsts.b.incomplisoin = 1;
+03793         dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
+03794                         gintsts.d32);
+03795 
+03796         return 1;
+03797 }
+03798 
+03814 int32_t dwc_otg_pcd_handle_incomplete_isoc_out_intr(dwc_otg_pcd_t * pcd)
+03815 {
+03816 
+03817         gintsts_data_t gintsts;
+03818 
+03819 #ifdef DWC_EN_ISOC
+03820         dwc_otg_dev_if_t *dev_if;
+03821         deptsiz_data_t deptsiz = {.d32 = 0 };
+03822         depctl_data_t depctl = {.d32 = 0 };
+03823         dsts_data_t dsts = {.d32 = 0 };
+03824         dwc_ep_t *dwc_ep;
+03825         int i;
+03826 
+03827         dev_if = GET_CORE_IF(pcd)->dev_if;
+03828 
+03829         for (i = 1; i <= dev_if->num_out_eps; ++i) {
+03830                 dwc_ep = &pcd->in_ep[i].dwc_ep;
+03831                 if (pcd->out_ep[i].dwc_ep.active &&
+03832                     pcd->out_ep[i].dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) {
+03833                         deptsiz.d32 =
+03834                             dwc_read_reg32(&dev_if->out_ep_regs[i]->doeptsiz);
+03835                         depctl.d32 =
+03836                             dwc_read_reg32(&dev_if->out_ep_regs[i]->doepctl);
+03837 
+03838                         if (depctl.b.epdis && deptsiz.d32) {
+03839                                 set_current_pkt_info(GET_CORE_IF(pcd),
+03840                                                      &pcd->out_ep[i].dwc_ep);
+03841                                 if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) {
+03842                                         dwc_ep->cur_pkt = 0;
+03843                                         dwc_ep->proc_buf_num =
+03844                                             (dwc_ep->proc_buf_num ^ 1) & 0x1;
+03845 
+03846                                         if (dwc_ep->proc_buf_num) {
+03847                                                 dwc_ep->cur_pkt_addr =
+03848                                                     dwc_ep->xfer_buff1;
+03849                                                 dwc_ep->cur_pkt_dma_addr =
+03850                                                     dwc_ep->dma_addr1;
+03851                                         } else {
+03852                                                 dwc_ep->cur_pkt_addr =
+03853                                                     dwc_ep->xfer_buff0;
+03854                                                 dwc_ep->cur_pkt_dma_addr =
+03855                                                     dwc_ep->dma_addr0;
+03856                                         }
+03857 
+03858                                 }
+03859 
+03860                                 dsts.d32 =
+03861                                     dwc_read_reg32(&GET_CORE_IF(pcd)->dev_if->
+03862                                                    dev_global_regs->dsts);
+03863                                 dwc_ep->next_frame = dsts.b.soffn;
+03864 
+03865                                 dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF
+03866                                                                   (pcd),
+03867                                                                   dwc_ep);
+03868                         }
+03869                 }
+03870         }
+03871 #else
+03872 
+03873         gintmsk_data_t intr_mask = {.d32 = 0 };
+03874 
+03875         DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
+03876                    "OUT ISOC Incomplete");
+03877 
+03878         intr_mask.b.incomplisoout = 1;
+03879         dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
+03880                          intr_mask.d32, 0);
+03881 
+03882 #endif                          /* DWC_EN_ISOC */
+03883 
+03884         /* Clear interrupt */
+03885         gintsts.d32 = 0;
+03886         gintsts.b.incomplisoout = 1;
+03887         dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
+03888                         gintsts.d32);
+03889 
+03890         return 1;
+03891 }
+03892 
+03897 int32_t dwc_otg_pcd_handle_in_nak_effective(dwc_otg_pcd_t * pcd)
+03898 {
+03899         dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if;
+03900         depctl_data_t diepctl = {.d32 = 0 };
+03901         depctl_data_t diepctl_rd = {.d32 = 0 };
+03902         gintmsk_data_t intr_mask = {.d32 = 0 };
+03903         gintsts_data_t gintsts;
+03904         int i;
+03905 
+03906         DWC_DEBUGPL(DBG_PCD, "Global IN NAK Effective\n");
+03907 
+03908         /* Disable all active IN EPs */
+03909         diepctl.b.epdis = 1;
+03910         diepctl.b.snak = 1;
+03911 
+03912         for (i = 0; i <= dev_if->num_in_eps; i++) {
+03913                 diepctl_rd.d32 =
+03914                     dwc_read_reg32(&dev_if->in_ep_regs[i]->diepctl);
+03915                 if (diepctl_rd.b.epena) {
+03916                         dwc_write_reg32(&dev_if->in_ep_regs[i]->diepctl,
+03917                                         diepctl.d32);
+03918                 }
+03919         }
+03920         /* Disable the Global IN NAK Effective Interrupt */
+03921         intr_mask.b.ginnakeff = 1;
+03922         dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
+03923                          intr_mask.d32, 0);
+03924 
+03925         /* Clear interrupt */
+03926         gintsts.d32 = 0;
+03927         gintsts.b.ginnakeff = 1;
+03928         dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
+03929                         gintsts.d32);
+03930 
+03931         return 1;
+03932 }
+03933 
+03938 int32_t dwc_otg_pcd_handle_out_nak_effective(dwc_otg_pcd_t * pcd)
+03939 {
+03940         gintmsk_data_t intr_mask = {.d32 = 0 };
+03941         gintsts_data_t gintsts;
+03942 
+03943         DWC_PRINTF("INTERRUPT Handler not implemented for %s\n",
+03944                    "Global IN NAK Effective\n");
+03945         /* Disable the Global IN NAK Effective Interrupt */
+03946         intr_mask.b.goutnakeff = 1;
+03947         dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk,
+03948                          intr_mask.d32, 0);
+03949 
+03950         /* Clear interrupt */
+03951         gintsts.d32 = 0;
+03952         gintsts.b.goutnakeff = 1;
+03953         dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts,
+03954                         gintsts.d32);
+03955 
+03956         return 1;
+03957 }
+03958 
+03971 int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd)
+03972 {
+03973         dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd);
+03974 #ifdef VERBOSE
+03975         dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
+03976 #endif
+03977         gintsts_data_t gintr_status;
+03978         int32_t retval = 0;
+03979 
+03980 #ifdef VERBOSE
+03981         DWC_DEBUGPL(DBG_ANY, "%s() gintsts=%08x  gintmsk=%08x\n",
+03982                     __func__,
+03983                     dwc_read_reg32(&global_regs->gintsts),
+03984                     dwc_read_reg32(&global_regs->gintmsk));
+03985 #endif
+03986 
+03987         if (dwc_otg_is_device_mode(core_if)) {
+03988                 DWC_SPINLOCK(pcd->lock);
+03989 #ifdef VERBOSE
+03990                 DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%08x  gintmsk=%08x\n",
+03991                             __func__,
+03992                             dwc_read_reg32(&global_regs->gintsts),
+03993                             dwc_read_reg32(&global_regs->gintmsk));
+03994 #endif
+03995 
+03996                 gintr_status.d32 = dwc_otg_read_core_intr(core_if);
+03997 
+03998                 DWC_DEBUGPL(DBG_PCDV, "%s: gintsts&gintmsk=%08x\n",
+03999                             __func__, gintr_status.d32);
+04000 
+04001                 if (gintr_status.b.sofintr) {
+04002                         retval |= dwc_otg_pcd_handle_sof_intr(pcd);
+04003                 }
+04004                 if (gintr_status.b.rxstsqlvl) {
+04005                         retval |=
+04006                             dwc_otg_pcd_handle_rx_status_q_level_intr(pcd);
+04007                 }
+04008                 if (gintr_status.b.nptxfempty) {
+04009                         retval |= dwc_otg_pcd_handle_np_tx_fifo_empty_intr(pcd);
+04010                 }
+04011                 if (gintr_status.b.ginnakeff) {
+04012                         retval |= dwc_otg_pcd_handle_in_nak_effective(pcd);
+04013                 }
+04014                 if (gintr_status.b.goutnakeff) {
+04015                         retval |= dwc_otg_pcd_handle_out_nak_effective(pcd);
+04016                 }
+04017                 if (gintr_status.b.i2cintr) {
+04018                         retval |= dwc_otg_pcd_handle_i2c_intr(pcd);
+04019                 }
+04020                 if (gintr_status.b.erlysuspend) {
+04021                         retval |= dwc_otg_pcd_handle_early_suspend_intr(pcd);
+04022                 }
+04023                 if (gintr_status.b.usbreset) {
+04024                         retval |= dwc_otg_pcd_handle_usb_reset_intr(pcd);
+04025                 }
+04026                 if (gintr_status.b.enumdone) {
+04027                         retval |= dwc_otg_pcd_handle_enum_done_intr(pcd);
+04028                 }
+04029                 if (gintr_status.b.isooutdrop) {
+04030                         retval |=
+04031                             dwc_otg_pcd_handle_isoc_out_packet_dropped_intr
+04032                             (pcd);
+04033                 }
+04034                 if (gintr_status.b.eopframe) {
+04035                         retval |=
+04036                             dwc_otg_pcd_handle_end_periodic_frame_intr(pcd);
+04037                 }
+04038                 if (gintr_status.b.epmismatch) {
+04039                         retval |= dwc_otg_pcd_handle_ep_mismatch_intr(core_if);
+04040                 }
+04041                 if (gintr_status.b.inepint) {
+04042                         if (!core_if->multiproc_int_enable) {
+04043                                 retval |= dwc_otg_pcd_handle_in_ep_intr(pcd);
+04044                         }
+04045                 }
+04046                 if (gintr_status.b.outepintr) {
+04047                         if (!core_if->multiproc_int_enable) {
+04048                                 retval |= dwc_otg_pcd_handle_out_ep_intr(pcd);
+04049                         }
+04050                 }
+04051                 if (gintr_status.b.incomplisoin) {
+04052                         retval |=
+04053                             dwc_otg_pcd_handle_incomplete_isoc_in_intr(pcd);
+04054                 }
+04055                 if (gintr_status.b.incomplisoout) {
+04056                         retval |=
+04057                             dwc_otg_pcd_handle_incomplete_isoc_out_intr(pcd);
+04058                 }
+04059 
+04060                 /* In MPI mode De vice Endpoints intterrupts are asserted 
+04061                  * without setting outepintr and inepint bits set, so these
+04062                  * Interrupt handlers are called without checking these bit-fields
+04063                  */
+04064                 if (core_if->multiproc_int_enable) {
+04065                         retval |= dwc_otg_pcd_handle_in_ep_intr(pcd);
+04066                         retval |= dwc_otg_pcd_handle_out_ep_intr(pcd);
+04067                 }
+04068 #ifdef VERBOSE
+04069                 DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%0x\n", __func__,
+04070                             dwc_read_reg32(&global_regs->gintsts));
+04071 #endif
+04072                 DWC_SPINUNLOCK(pcd->lock);
+04073         }
+04074         return retval;
+04075 }
+04076 
+04077 #endif                          /* DWC_HOST_ONLY */
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__intr_8c.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__intr_8c.html new file mode 100644 index 000000000000..0356970db980 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__intr_8c.html @@ -0,0 +1,1599 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_pcd_intr.c File Reference + + + + + + +

dwc_otg_pcd_intr.c File Reference

This file contains the implementation of the PCD Interrupt handlers. More... +

+#include "dwc_otg_pcd.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Defines

+#define DEBUG_EP0
#define CLEAR_IN_EP_INTR(__core_if, __epnum, __intr)
#define CLEAR_OUT_EP_INTR(__core_if, __epnum, __intr)

Functions

+static void dwc_otg_pcd_update_otg (dwc_otg_pcd_t *pcd, const unsigned reset)
 This function updates OTG.
+static void print_ep0_state (dwc_otg_pcd_t *pcd)
 This function prints the ep0 state for debug purposes.
+static dwc_otg_pcd_ep_tget_in_ep (dwc_otg_pcd_t *pcd, uint32_t ep_num)
 This function returns pointer to in ep struct with number ep_num.
+static dwc_otg_pcd_ep_tget_out_ep (dwc_otg_pcd_t *pcd, uint32_t ep_num)
 This function returns pointer to out ep struct with number ep_num.
+dwc_otg_pcd_ep_tget_ep_by_addr (dwc_otg_pcd_t *pcd, u16 wIndex)
 This functions gets a pointer to an EP from the wIndex address value of the control request.
+void start_next_request (dwc_otg_pcd_ep_t *ep)
 Tasklet.
int32_t dwc_otg_pcd_handle_sof_intr (dwc_otg_pcd_t *pcd)
 This function handles the SOF Interrupts.
int32_t dwc_otg_pcd_handle_rx_status_q_level_intr (dwc_otg_pcd_t *pcd)
 This function handles the Rx Status Queue Level Interrupt, which indicates that there is a least one packet in the Rx FIFO.
static int get_ep_of_last_in_token (dwc_otg_core_if_t *core_if)
 This function examines the Device IN Token Learning Queue to determine the EP number of the last IN token received.
int32_t dwc_otg_pcd_handle_np_tx_fifo_empty_intr (dwc_otg_pcd_t *pcd)
 This interrupt occurs when the non-periodic Tx FIFO is half-empty.
static int32_t write_empty_tx_fifo (dwc_otg_pcd_t *pcd, uint32_t epnum)
 This function is called when dedicated Tx FIFO Empty interrupt occurs.
void dwc_otg_pcd_stop (dwc_otg_pcd_t *pcd)
 This function is called when the Device is disconnected.
int32_t dwc_otg_pcd_handle_i2c_intr (dwc_otg_pcd_t *pcd)
 This interrupt indicates that .
int32_t dwc_otg_pcd_handle_early_suspend_intr (dwc_otg_pcd_t *pcd)
 This interrupt indicates that .
static void ep0_out_start (dwc_otg_core_if_t *core_if, dwc_otg_pcd_t *pcd)
 This function configures EPO to receive SETUP packets.
int32_t dwc_otg_pcd_handle_usb_reset_intr (dwc_otg_pcd_t *pcd)
 This interrupt occurs when a USB Reset is detected.
static int get_device_speed (dwc_otg_core_if_t *core_if)
 Get the device speed from the device status register and convert it to USB speed constant.
int32_t dwc_otg_pcd_handle_enum_done_intr (dwc_otg_pcd_t *pcd)
 Read the device status register and set the device speed in the data structure.
int32_t dwc_otg_pcd_handle_isoc_out_packet_dropped_intr (dwc_otg_pcd_t *pcd)
 This interrupt indicates that the ISO OUT Packet was dropped due to Rx FIFO full or Rx Status Queue Full.
int32_t dwc_otg_pcd_handle_end_periodic_frame_intr (dwc_otg_pcd_t *pcd)
 This interrupt indicates the end of the portion of the micro-frame for periodic transactions.
int32_t dwc_otg_pcd_handle_ep_mismatch_intr (dwc_otg_core_if_t *core_if)
 This interrupt indicates that EP of the packet on the top of the non-periodic Tx FIFO does not match EP of the IN Token received.
+static void ep0_do_stall (dwc_otg_pcd_t *pcd, const int err_val)
 This funcion stalls EP0.
static void do_gadget_setup (dwc_otg_pcd_t *pcd, usb_device_request_t *ctrl)
 This functions delegates the setup command to the gadget driver.
+static void do_setup_in_status_phase (dwc_otg_pcd_t *pcd)
 This function starts the Zero-Length Packet for the IN status phase of a 2 stage control transfer.
+static void do_setup_out_status_phase (dwc_otg_pcd_t *pcd)
 This function starts the Zero-Length Packet for the OUT status phase of a 2 stage control transfer.
static void pcd_clear_halt (dwc_otg_pcd_t *pcd, dwc_otg_pcd_ep_t *ep)
 Clear the EP halt (STALL) and if pending requests start the transfer.
void do_test_mode (void *data)
 This function is called when the SET_FEATURE TEST_MODE Setup packet is sent from the host.
static void do_get_status (dwc_otg_pcd_t *pcd)
 This function process the GET_STATUS Setup Commands.
static void do_set_feature (dwc_otg_pcd_t *pcd)
 This function process the SET_FEATURE Setup Commands.
static void do_clear_feature (dwc_otg_pcd_t *pcd)
 This function process the CLEAR_FEATURE Setup Commands.
+static void do_set_address (dwc_otg_pcd_t *pcd)
 This function process the SET_ADDRESS Setup Commands.
static void pcd_setup (dwc_otg_pcd_t *pcd)
 This function processes SETUP commands.
+static int32_t ep0_complete_request (dwc_otg_pcd_ep_t *ep)
 This function completes the ep0 control transfer.
static void complete_ep (dwc_otg_pcd_ep_t *ep)
 This function completes the request for the EP.
+static void dwc_otg_pcd_handle_iso_bna (dwc_otg_pcd_ep_t *ep)
 This function BNA interrupt for Isochronous EPs.
void set_current_pkt_info (dwc_otg_core_if_t *core_if, dwc_ep_t *ep)
 This function sets latest iso packet information(non-PTI mode).
static void set_ddma_iso_pkts_info (dwc_otg_core_if_t *core_if, dwc_ep_t *dwc_ep)
 This function sets latest iso packet information(DDMA mode).
static void reinit_ddma_iso_xfer (dwc_otg_core_if_t *core_if, dwc_ep_t *dwc_ep)
 This function reinitialize DMA Descriptors for Isochronous transfer.
static uint32_t handle_iso_out_pkt_dropped (dwc_otg_core_if_t *core_if, dwc_ep_t *dwc_ep)
 This function is to handle Iso EP transfer complete interrupt in case Iso out packet was dropped.
static uint32_t set_iso_pkts_info (dwc_otg_core_if_t *core_if, dwc_ep_t *ep)
 This function sets iso packets information(PTI mode).
static void complete_iso_ep (dwc_otg_pcd_t *pcd, dwc_otg_pcd_ep_t *ep)
 This function is to handle Iso EP transfer complete interrupt.
static void handle_ep0 (dwc_otg_pcd_t *pcd)
 This function handles EP0 Control transfers.
+static void restart_transfer (dwc_otg_pcd_t *pcd, const uint32_t epnum)
 Restart transfer.
+static void handle_in_ep_disable_intr (dwc_otg_pcd_t *pcd, const uint32_t epnum)
 handle the IN EP disable interrupt.
static void handle_in_ep_timeout_intr (dwc_otg_pcd_t *pcd, const uint32_t epnum)
 Handler for the IN EP timeout handshake interrupt.
static int32_t handle_in_ep_nak_intr (dwc_otg_pcd_t *pcd, const uint32_t epnum)
 Handler for the IN EP NAK interrupt.
static int32_t handle_out_ep_babble_intr (dwc_otg_pcd_t *pcd, const uint32_t epnum)
 Handler for the OUT EP Babble interrupt.
static int32_t handle_out_ep_nak_intr (dwc_otg_pcd_t *pcd, const uint32_t epnum)
 Handler for the OUT EP NAK interrupt.
static int32_t handle_out_ep_nyet_intr (dwc_otg_pcd_t *pcd, const uint32_t epnum)
 Handler for the OUT EP NYET interrupt.
static int32_t dwc_otg_pcd_handle_in_ep_intr (dwc_otg_pcd_t *pcd)
 This interrupt indicates that an IN EP has a pending Interrupt.
static int32_t dwc_otg_pcd_handle_out_ep_intr (dwc_otg_pcd_t *pcd)
 This interrupt indicates that an OUT EP has a pending Interrupt.
int32_t dwc_otg_pcd_handle_incomplete_isoc_in_intr (dwc_otg_pcd_t *pcd)
 Incomplete ISO IN Transfer Interrupt.
int32_t dwc_otg_pcd_handle_incomplete_isoc_out_intr (dwc_otg_pcd_t *pcd)
 Incomplete ISO OUT Transfer Interrupt.
+int32_t dwc_otg_pcd_handle_in_nak_effective (dwc_otg_pcd_t *pcd)
 This function handles the Global IN NAK Effective interrupt.
+int32_t dwc_otg_pcd_handle_out_nak_effective (dwc_otg_pcd_t *pcd)
 OUT NAK Effective.
int32_t dwc_otg_pcd_handle_intr (dwc_otg_pcd_t *pcd)
 This function should be called on every hardware interrupt.
+


Detailed Description

+This file contains the implementation of the PCD Interrupt handlers. +

+The PCD handles the device interrupts. Many conditions can cause a device interrupt. When an interrupt occurs, the device interrupt service routine determines the cause of the interrupt and dispatches handling to the appropriate function. These interrupt handling functions are described below. All interrupt registers are processed from LSB to MSB. +

+Definition in file dwc_otg_pcd_intr.c.


Define Documentation

+ +
+
+ + + + + + + + + + + + + + + +
#define CLEAR_IN_EP_INTR (__core_if,
__epnum,
__intr   ) 
+
+
+ +

+Value:

do { \
+                diepint_data_t diepint = {.d32=0}; \
+                diepint.b.__intr = 1; \
+                dwc_write_reg32(&__core_if->dev_if->in_ep_regs[__epnum]->diepint, \
+                diepint.d32); \
+} while (0)
+
+
+

+ +

+
+ + + + + + + + + + + + + + + +
#define CLEAR_OUT_EP_INTR (__core_if,
__epnum,
__intr   ) 
+
+
+ +

+Value:

do { \
+                doepint_data_t doepint = {.d32=0}; \
+                doepint.b.__intr = 1; \
+                dwc_write_reg32(&__core_if->dev_if->out_ep_regs[__epnum]->doepint, \
+                doepint.d32); \
+} while (0)
+
+
+

+


Function Documentation

+ +
+
+ + + + + + + + + +
int32_t dwc_otg_pcd_handle_sof_intr (dwc_otg_pcd_t pcd  ) 
+
+
+ +

+This function handles the SOF Interrupts. +

+At this time the SOF Interrupt is disabled. +

+Definition at line 252 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_pcd_handle_rx_status_q_level_intr (dwc_otg_pcd_t pcd  ) 
+
+
+ +

+This function handles the Rx Status Queue Level Interrupt, which indicates that there is a least one packet in the Rx FIFO. +

+The packets are moved from the FIFO to memory, where they will be processed when the Endpoint Interrupt Register indicates Transfer Complete or SETUP Phase Done.

+Repeat the following until the Rx Status Queue is empty:

    +
  1. Read the Receive Status Pop Register (GRXSTSP) to get Packet info
  2. If Receive FIFO is empty then skip to step Clear the interrupt and exit
  3. If SETUP Packet call dwc_otg_read_setup_packet to copy the SETUP data to the buffer
  4. If OUT Data Packet call dwc_otg_read_packet to copy the data to the destination buffer
+ +

+

Todo:
NGS Check for buffer overflow?
+ +

+Definition at line 285 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
static int get_ep_of_last_in_token (dwc_otg_core_if_t core_if  )  [inline, static]
+
+
+ +

+This function examines the Device IN Token Learning Queue to determine the EP number of the last IN token received. +

+This implementation is for the Mass Storage device where there are only 2 IN EPs (Control-IN and BULK-IN).

+The EP numbers for the first six IN Tokens are in DTKNQR1 and there are 8 EP Numbers in each of the other possible DTKNQ Registers.

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+

Todo:
Find a simpler way to calculate the max queue position.
+ +

+Definition at line 378 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_pcd_handle_np_tx_fifo_empty_intr (dwc_otg_pcd_t pcd  ) 
+
+
+ +

+This interrupt occurs when the non-periodic Tx FIFO is half-empty. +

+The active request is checked for the next packet to be loaded into the non-periodic Tx FIFO. +

+Definition at line 451 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static int32_t write_empty_tx_fifo (dwc_otg_pcd_t pcd,
uint32_t  epnum 
) [static]
+
+
+ +

+This function is called when dedicated Tx FIFO Empty interrupt occurs. +

+The active request is checked for the next packet to be loaded into apropriate Tx FIFO. +

+Definition at line 515 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
void dwc_otg_pcd_stop (dwc_otg_pcd_t pcd  ) 
+
+
+ +

+This function is called when the Device is disconnected. +

+It stops any active requests and informs the Gadget driver of the disconnect. +

+

Todo:
NGS Flush Periodic FIFOs
+ +

+Definition at line 573 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_pcd_handle_i2c_intr (dwc_otg_pcd_t pcd  ) 
+
+
+ +

+This interrupt indicates that . +

+.. +

+Definition at line 632 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_pcd_handle_early_suspend_intr (dwc_otg_pcd_t pcd  ) 
+
+
+ +

+This interrupt indicates that . +

+.. +

+Definition at line 653 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static void ep0_out_start (dwc_otg_core_if_t core_if,
dwc_otg_pcd_t pcd 
) [inline, static]
+
+
+ +

+This function configures EPO to receive SETUP packets. +

+

Todo:
NGS: Update the comments from the HW FS.
+
    +
  1. Program the following fields in the endpoint specific registers for Control OUT EP 0, in order to receive a setup packet
+
    +
  • DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back setup packets)
  • DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back to back setup packets)
      +
    • In DMA mode, DOEPDMA0 Register with a memory address to store any setup packets received
    +
+

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
pcd Programming view of the PCD.
+
+ +

+put here as for Hermes mode deptisz register should not be written

+

Todo:
dma needs to handle multiple setup packets (up to 3)
+

+DMA Descriptor Setup

+DOEPDMA0 Register write

+put here as for Hermes mode deptisz register should not be written

+DOEPCTL0 Register write +

+Definition at line 684 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_pcd_handle_usb_reset_intr (dwc_otg_pcd_t pcd  ) 
+
+
+ +

+This interrupt occurs when a USB Reset is detected. +

+When the USB Reset Interrupt occurs the device state is set to DEFAULT and the EP0 state is set to IDLE.

    +
  1. Set the NAK bit for all OUT endpoints (DOEPCTLn.SNAK = 1)
  2. Unmask the following interrupt bits
      +
    • DAINTMSK.INEP0 = 1 (Control 0 IN endpoint)
    +
+
    +
  • DAINTMSK.OUTEP0 = 1 (Control 0 OUT endpoint)
  • DOEPMSK.SETUP = 1
  • DOEPMSK.XferCompl = 1
  • DIEPMSK.XferCompl = 1
  • DIEPMSK.TimeOut = 1
+
    +
  1. Program the following fields in the endpoint specific registers for Control OUT EP 0, in order to receive a setup packet
+
    +
  • DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back setup packets)
  • DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back to back setup packets)
      +
    • In DMA mode, DOEPDMA0 Register with a memory address to store any setup packets received At this point, all the required initialization, except for enabling the control 0 OUT endpoint is done, for receiving SETUP packets.
    +
+ +

+Definition at line 772 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
static int get_device_speed (dwc_otg_core_if_t core_if  )  [static]
+
+
+ +

+Get the device speed from the device status register and convert it to USB speed constant. +

+

Parameters:
+ + +
core_if Programming view of DWC_otg controller.
+
+ +

+Definition at line 928 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_pcd_handle_enum_done_intr (dwc_otg_pcd_t pcd  ) 
+
+
+ +

+Read the device status register and set the device speed in the data structure. +

+Set up EP0 to receive SETUP packets by calling dwc_ep0_activate. +

+Definition at line 956 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_pcd_handle_isoc_out_packet_dropped_intr (dwc_otg_pcd_t pcd  ) 
+
+
+ +

+This interrupt indicates that the ISO OUT Packet was dropped due to Rx FIFO full or Rx Status Queue Full. +

+If this interrupt occurs read all the data from the Rx FIFO. +

+Definition at line 1051 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_pcd_handle_end_periodic_frame_intr (dwc_otg_pcd_t pcd  ) 
+
+
+ +

+This interrupt indicates the end of the portion of the micro-frame for periodic transactions. +

+If there is a periodic transaction for the next frame, load the packets into the EP periodic Tx FIFO. +

+Definition at line 1077 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_pcd_handle_ep_mismatch_intr (dwc_otg_core_if_t core_if  ) 
+
+
+ +

+This interrupt indicates that EP of the packet on the top of the non-periodic Tx FIFO does not match EP of the IN Token received. +

+The "Device IN Token Queue" Registers are read to determine the order the IN Tokens have been received. The non-periodic Tx FIFO is flushed, so it can be reloaded in the order seen in the IN Token Queue. +

+Definition at line 1105 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static void do_gadget_setup (dwc_otg_pcd_t pcd,
usb_device_request_t *  ctrl 
) [inline, static]
+
+
+ +

+This functions delegates the setup command to the gadget driver. +

+ +

+

Todo:
This is a g_file_storage gadget driver specific workaround: a DELAYED_STATUS result from the fsg_setup routine will result in the gadget queueing a EP0 IN status phase for a two-stage control transfer. Exactly the same as a SET_CONFIGURATION/SET_INTERFACE except that this is a class specific request. Need a generic way to know when the gadget driver will queue the status phase. Can we assume when we call the gadget driver setup() function that it will always queue and require the following flag? Need to look into this.
+ +

+Definition at line 1138 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static void pcd_clear_halt (dwc_otg_pcd_t pcd,
dwc_otg_pcd_ep_t ep 
) [inline, static]
+
+
+ +

+Clear the EP halt (STALL) and if pending requests start the transfer. +

+ +

+

Todo:
FIXME: this causes an EP mismatch in DMA mode. epmismatch not yet implemented.
+ +

+Definition at line 1245 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
void do_test_mode (void *  data  ) 
+
+
+ +

+This function is called when the SET_FEATURE TEST_MODE Setup packet is sent from the host. +

+The Device Control register is written with the Test Mode bits set to the specified Test Mode. This is done as a tasklet so that the "Status" phase of the control transfer completes before transmitting the TEST packets.

+

Todo:
This has not been tested since the tasklet struct was put into the PCD struct!
+ +

+Definition at line 1284 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
static void do_get_status (dwc_otg_pcd_t pcd  )  [inline, static]
+
+
+ +

+This function process the GET_STATUS Setup Commands. +

+ +

+

Todo:
check for EP stall
+ +

+Definition at line 1321 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
static void do_set_feature (dwc_otg_pcd_t pcd  )  [inline, static]
+
+
+ +

+This function process the SET_FEATURE Setup Commands. +

+ +

+

Todo:
This has not been tested since the tasklet struct was put into the PCD struct!
+

+

Todo:
Is the gotgctl.devhnpen cleared by a USB Reset?
+ +

+Definition at line 1369 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
static void do_clear_feature (dwc_otg_pcd_t pcd  )  [inline, static]
+
+
+ +

+This function process the CLEAR_FEATURE Setup Commands. +

+ +

+

Todo:
Add CLEAR_FEATURE for TEST modes.
+ +

+Definition at line 1472 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
static void pcd_setup (dwc_otg_pcd_t pcd  )  [inline, static]
+
+
+ +

+This function processes SETUP commands. +

+In Linux, the USB Command processing is done in two places - the first being the PCD and the second in the Gadget Driver (for example, the File-Backed Storage Gadget Driver).

+ + + + + + + + + + + + + + + + + + + + + + + + + +
Command Driver Description

+

GET_STATUS PCD Command is processed as defined in chapter 9 of the USB 2.0 Specification chapter 9

+

CLEAR_FEATURE PCD The Device and Endpoint requests are the ENDPOINT_HALT feature is procesed, all others the interface requests are ignored.

+

SET_FEATURE PCD The Device and Endpoint requests are processed by the PCD. Interface requests are passed to the Gadget Driver.

+

SET_ADDRESS PCD Program the DCFG reg, with device address received

+

GET_DESCRIPTOR Gadget Driver Return the requested descriptor

+

SET_DESCRIPTOR Gadget Driver Optional - not implemented by any of the existing Gadget Drivers.

+

SET_CONFIGURATION Gadget Driver Disable all EPs and enable EPs for new configuration.

+

GET_CONFIGURATION Gadget Driver Return the current configuration

+

SET_INTERFACE Gadget Driver Disable all EPs and enable EPs for new configuration.

+

GET_INTERFACE Gadget Driver Return the current interface.

+

SYNC_FRAME PCD Display debug message.
+

+When the SETUP Phase Done interrupt occurs, the PCD SETUP commands are processed by pcd_setup. Calling the Function Driver's setup function from pcd_setup processes the gadget SETUP commands. +

+

Todo:
handle > 1 setup packet , assert error for now
+

+

Todo:
NGS: Handle bad setup packet?
+ +

+Definition at line 1580 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
static void complete_ep (dwc_otg_pcd_ep_t ep  )  [static]
+
+
+ +

+This function completes the request for the EP. +

+If there are additional requests for the EP in the queue they will be started. +

+Definition at line 1911 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
void set_current_pkt_info (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
)
+
+
+ +

+This function sets latest iso packet information(non-PTI mode). +

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to start the transfer on.
+
+ +

+Definition at line 2274 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static void set_ddma_iso_pkts_info (dwc_otg_core_if_t core_if,
dwc_ep_t dwc_ep 
) [static]
+
+
+ +

+This function sets latest iso packet information(DDMA mode). +

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
dwc_ep The EP to start the transfer on.
+
+ +

+Reinit closed DMA Descriptors

+ISO OUT EP

+ISO IN EP +

+Definition at line 2322 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static void reinit_ddma_iso_xfer (dwc_otg_core_if_t core_if,
dwc_ep_t dwc_ep 
) [static]
+
+
+ +

+This function reinitialize DMA Descriptors for Isochronous transfer. +

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
dwc_ep The EP to start the transfer on.
+
+ +

+Buffer 0 descriptors setup

+Buffer 1 descriptors setup

+Reinit closed DMA Descriptors

+ISO OUT EP

+ISO IN EP +

+Definition at line 2486 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static uint32_t handle_iso_out_pkt_dropped (dwc_otg_core_if_t core_if,
dwc_ep_t dwc_ep 
) [static]
+
+
+ +

+This function is to handle Iso EP transfer complete interrupt in case Iso out packet was dropped. +

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
dwc_ep The EP for wihich transfer complete was asserted
+
+ +

+Re-enable endpoint, clear nak +

+Definition at line 2620 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static uint32_t set_iso_pkts_info (dwc_otg_core_if_t core_if,
dwc_ep_t ep 
) [static]
+
+
+ +

+This function sets iso packets information(PTI mode). +

+

Parameters:
+ + + +
core_if Programming view of DWC_otg controller.
ep The EP to start the transfer on.
+
+ +

+Buffer 0 descriptors setup

+Buffer 1 descriptors setup +

+Definition at line 2690 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static void complete_iso_ep (dwc_otg_pcd_t pcd,
dwc_otg_pcd_ep_t ep 
) [static]
+
+
+ +

+This function is to handle Iso EP transfer complete interrupt. +

+

Parameters:
+ + + +
pcd The PCD
ep The EP for which transfer complete was asserted
+
+ +

+Definition at line 2766 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
static void handle_ep0 (dwc_otg_pcd_t pcd  )  [static]
+
+
+ +

+This function handles EP0 Control transfers. +

+The state of the control tranfers are tracked in ep0state. +

+Definition at line 2843 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static void handle_in_ep_timeout_intr (dwc_otg_pcd_t pcd,
const uint32_t  epnum 
) [inline, static]
+
+
+ +

+Handler for the IN EP timeout handshake interrupt. +

+ +

+

Todo:
NGS Check EP type. Implement for Periodic EPs
+ +

+Definition at line 3080 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static int32_t handle_in_ep_nak_intr (dwc_otg_pcd_t pcd,
const uint32_t  epnum 
) [inline, static]
+
+
+ +

+Handler for the IN EP NAK interrupt. +

+ +

+

Todo:
implement ISR
+ +

+Definition at line 3141 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static int32_t handle_out_ep_babble_intr (dwc_otg_pcd_t pcd,
const uint32_t  epnum 
) [inline, static]
+
+
+ +

+Handler for the OUT EP Babble interrupt. +

+ +

+

Todo:
implement ISR
+ +

+Definition at line 3166 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static int32_t handle_out_ep_nak_intr (dwc_otg_pcd_t pcd,
const uint32_t  epnum 
) [inline, static]
+
+
+ +

+Handler for the OUT EP NAK interrupt. +

+ +

+

Todo:
implement ISR
+ +

+Definition at line 3192 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static int32_t handle_out_ep_nyet_intr (dwc_otg_pcd_t pcd,
const uint32_t  epnum 
) [inline, static]
+
+
+ +

+Handler for the OUT EP NYET interrupt. +

+ +

+

Todo:
implement ISR
+ +

+Definition at line 3217 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
static int32_t dwc_otg_pcd_handle_in_ep_intr (dwc_otg_pcd_t pcd  )  [static]
+
+
+ +

+This interrupt indicates that an IN EP has a pending Interrupt. +

+The sequence for handling the IN EP interrupt is shown below:

    +
  1. Read the Device All Endpoint Interrupt register
  2. Repeat the following for each IN EP interrupt bit set (from LSB to MSB).
  3. Read the Device Endpoint Interrupt (DIEPINTn) register
  4. If "Transfer Complete" call the request complete function
  5. If "Endpoint Disabled" complete the EP disable procedure.
  6. If "AHB Error Interrupt" log error
  7. If "Time-out Handshake" log error
  8. If "IN Token Received when TxFIFO Empty" write packet to Tx FIFO.
  9. If "IN Token EP Mismatch" (disable, this is handled by EP Mismatch Interrupt)
+ +

+IN Token received with TxF Empty

+IN Token Received with EP mismatch

+IN Endpoint NAK Effective

+IN EP Tx FIFO Empty Intr

+IN EP BNA Intr +

+Definition at line 3255 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
static int32_t dwc_otg_pcd_handle_out_ep_intr (dwc_otg_pcd_t pcd  )  [static]
+
+
+ +

+This interrupt indicates that an OUT EP has a pending Interrupt. +

+The sequence for handling the OUT EP interrupt is shown below:

    +
  1. Read the Device All Endpoint Interrupt register
  2. Repeat the following for each OUT EP interrupt bit set (from LSB to MSB).
  3. Read the Device Endpoint Interrupt (DOEPINTn) register
  4. If "Transfer Complete" call the request complete function
  5. If "Endpoint Disabled" complete the EP disable procedure.
  6. If "AHB Error Interrupt" log error
  7. If "Setup Phase Done" process Setup Packet (See Standard USB Command Processing)
+ +

+OUT EP BNA Intr +

+Definition at line 3522 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_pcd_handle_incomplete_isoc_in_intr (dwc_otg_pcd_t pcd  ) 
+
+
+ +

+Incomplete ISO IN Transfer Interrupt. +

+This interrupt indicates one of the following conditions occurred while transmitting an ISOC transaction.

    +
  • Corrupted IN Token for ISOC EP.
  • Packet not complete in FIFO. The follow actions will be taken:
      +
    1. Determine the EP
    2. Set incomplete flag in dwc_ep structure
    3. Disable EP; when "Endpoint Disabled" interrupt is received Flush FIFO
    +
+ +

+Definition at line 3725 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_pcd_handle_incomplete_isoc_out_intr (dwc_otg_pcd_t pcd  ) 
+
+
+ +

+Incomplete ISO OUT Transfer Interrupt. +

+This interrupt indicates that the core has dropped an ISO OUT packet. The following conditions can be the cause:

    +
  • FIFO Full, the entire packet would not fit in the FIFO.
  • CRC Error
  • Corrupted Token The follow actions will be taken:
      +
    1. Determine the EP
    2. Set incomplete flag in dwc_ep structure
    3. Read any data from the FIFO
    4. Disable EP. when "Endpoint Disabled" interrupt is received re-enable EP.
    +
+ +

+Definition at line 3814 of file dwc_otg_pcd_intr.c. +

+

+ +

+
+ + + + + + + + + +
int32_t dwc_otg_pcd_handle_intr (dwc_otg_pcd_t pcd  ) 
+
+
+ +

+This function should be called on every hardware interrupt. +

+The PCD handles the device interrupts. Many conditions can cause a device interrupt. When an interrupt occurs, the device interrupt service routine determines the cause of the interrupt and dispatches handling to the appropriate function. These interrupt handling functions are described below.

+All interrupt registers are processed from LSB to MSB. +

+Definition at line 3971 of file dwc_otg_pcd_intr.c. +

+

+


Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__linux_8c-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__linux_8c-source.html new file mode 100644 index 000000000000..4eb0db1b6e0b --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__linux_8c-source.html @@ -0,0 +1,997 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_pcd_linux.c Source File + + + + + + +

dwc_otg_pcd_linux.c

Go to the documentation of this file.
00001  /* ==========================================================================
+00002   * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_linux.c $
+00003   * $Revision: #7 $
+00004   * $Date: 2009/04/03 $
+00005   * $Change: 1225160 $
+00006   *
+00007   * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008   * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009   * otherwise expressly agreed to in writing between Synopsys and you.
+00010   *
+00011   * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012   * any End User Software License Agreement or Agreement for Licensed Product
+00013   * with Synopsys or any supplement thereto. You are permitted to use and
+00014   * redistribute this Software in source and binary forms, with or without
+00015   * modification, provided that redistributions of source code must retain this
+00016   * notice. You may not view, use, disclose, copy or distribute this file or
+00017   * any information contained herein except pursuant to this license grant from
+00018   * Synopsys. If you do not agree with this notice, including the disclaimer
+00019   * below, then you are not authorized to use the Software.
+00020   *
+00021   * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024   * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031   * DAMAGE.
+00032   * ========================================================================== */
+00033 #ifndef DWC_HOST_ONLY
+00034 
+00056 #include <linux/kernel.h>
+00057 #include <linux/module.h>
+00058 #include <linux/moduleparam.h>
+00059 #include <linux/init.h>
+00060 #include <linux/device.h>
+00061 #include <linux/errno.h>
+00062 #include <linux/list.h>
+00063 #include <linux/interrupt.h>
+00064 #include <linux/string.h>
+00065 #include <linux/dma-mapping.h>
+00066 #include <linux/version.h>
+00067 
+00068 #ifdef LM_INTERFACE
+00069 # include <asm/arch/regs-irq.h>
+00070 # include <asm/arch/lm.h>
+00071 # include <asm/arch/irqs.h>
+00072 #endif
+00073 
+00074 #include <asm/io.h>
+00075 # include <linux/usb_ch9.h>
+00076 #include <linux/usb_gadget.h>
+00077 
+00078 #include "dwc_otg_pcd_if.h"
+00079 #include "dwc_otg_driver.h"
+00080 #include "dwc_otg_dbg.h"
+00081 
+00082 static struct gadget_wrapper {
+00083         dwc_otg_pcd_t *pcd;
+00084 
+00085         struct usb_gadget gadget;
+00086         struct usb_gadget_driver *driver;
+00087 
+00088         struct usb_ep ep0;
+00089         struct usb_ep in_ep[16];
+00090         struct usb_ep out_ep[16];
+00091 
+00092 } *gadget_wrapper;
+00093 
+00094 /* Display the contents of the buffer */
+00095 extern void dump_msg(const u8 * buf, unsigned int length);
+00096 
+00097 /* USB Endpoint Operations */
+00098 /*
+00099  * The following sections briefly describe the behavior of the Gadget
+00100  * API endpoint operations implemented in the DWC_otg driver
+00101  * software. Detailed descriptions of the generic behavior of each of
+00102  * these functions can be found in the Linux header file
+00103  * include/linux/usb_gadget.h.
+00104  *
+00105  * The Gadget API provides wrapper functions for each of the function
+00106  * pointers defined in usb_ep_ops. The Gadget Driver calls the wrapper
+00107  * function, which then calls the underlying PCD function. The
+00108  * following sections are named according to the wrapper
+00109  * functions. Within each section, the corresponding DWC_otg PCD
+00110  * function name is specified.
+00111  *
+00112  */
+00113 
+00121 static int ep_enable(struct usb_ep *usb_ep,
+00122                      const struct usb_endpoint_descriptor *ep_desc)
+00123 {
+00124         int retval;
+00125 
+00126         DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, ep_desc);
+00127 
+00128         if (!usb_ep || !ep_desc || ep_desc->bDescriptorType != USB_DT_ENDPOINT) {
+00129                 DWC_WARN("%s, bad ep or descriptor\n", __func__);
+00130                 return -EINVAL;
+00131         }
+00132         if (usb_ep == &gadget_wrapper->ep0) {
+00133                 DWC_WARN("%s, bad ep(0)\n", __func__);
+00134                 return -EINVAL;
+00135         }
+00136 
+00137         /* Check FIFO size? */
+00138         if (!ep_desc->wMaxPacketSize) {
+00139                 DWC_WARN("%s, bad %s maxpacket\n", __func__, usb_ep->name);
+00140                 return -ERANGE;
+00141         }
+00142 
+00143         if (!gadget_wrapper->driver ||
+00144             gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
+00145                 DWC_WARN("%s, bogus device state\n", __func__);
+00146                 return -ESHUTDOWN;
+00147         }
+00148 
+00149         retval = dwc_otg_pcd_ep_enable(gadget_wrapper->pcd,
+00150                                        (const uint8_t *)ep_desc,
+00151                                        (void *)usb_ep);
+00152         if (retval) {
+00153                 DWC_WARN("dwc_otg_pcd_ep_enable failed\n");
+00154                 return -EINVAL;
+00155         }
+00156 
+00157         usb_ep->maxpacket = le16_to_cpu(ep_desc->wMaxPacketSize);
+00158 
+00159         return 0;
+00160 }
+00161 
+00170 static int ep_disable(struct usb_ep *usb_ep)
+00171 {
+00172         int retval;
+00173 
+00174         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, usb_ep);
+00175         if (!usb_ep) {
+00176                 DWC_DEBUGPL(DBG_PCD, "%s, %s not enabled\n", __func__,
+00177                             usb_ep ? usb_ep->name : NULL);
+00178                 return -EINVAL;
+00179         }
+00180 
+00181         retval = dwc_otg_pcd_ep_disable(gadget_wrapper->pcd, usb_ep);
+00182         if (retval) {
+00183                 retval = -EINVAL;
+00184         }
+00185 
+00186         return retval;
+00187 }
+00188 
+00196 static struct usb_request *dwc_otg_pcd_alloc_request(struct usb_ep *ep,
+00197                                                      gfp_t gfp_flags)
+00198 {
+00199         struct usb_request *usb_req;
+00200 
+00201         DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d)\n", __func__, ep, gfp_flags);
+00202         if (0 == ep) {
+00203                 DWC_WARN("%s() %s\n", __func__, "Invalid EP!\n");
+00204                 return 0;
+00205         }
+00206         usb_req = kmalloc(sizeof(*usb_req), gfp_flags);
+00207         if (0 == usb_req) {
+00208                 DWC_WARN("%s() %s\n", __func__, "request allocation failed!\n");
+00209                 return 0;
+00210         }
+00211         memset(usb_req, 0, sizeof(*usb_req));
+00212         usb_req->dma = DWC_INVALID_DMA_ADDR;
+00213 
+00214         return usb_req;
+00215 }
+00216 
+00223 static void dwc_otg_pcd_free_request(struct usb_ep *ep, struct usb_request *req)
+00224 {
+00225         DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, ep, req);
+00226 
+00227         if (0 == ep || 0 == req) {
+00228                 DWC_WARN("%s() %s\n", __func__,
+00229                          "Invalid ep or req argument!\n");
+00230                 return;
+00231         }
+00232 
+00233         kfree(req);
+00234 }
+00235 
+00246 static void *dwc_otg_pcd_alloc_buffer(struct usb_ep *usb_ep, unsigned bytes,
+00247                                       dma_addr_t * dma, gfp_t gfp_flags)
+00248 {
+00249         void *buf;
+00250         dwc_otg_pcd_t *pcd = 0;
+00251 
+00252         pcd = gadget_wrapper->pcd;
+00253 
+00254         DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d,%p,%0x)\n", __func__, usb_ep, bytes,
+00255                     dma, gfp_flags);
+00256 
+00257         /* Check dword alignment */
+00258         if ((bytes & 0x3UL) != 0) {
+00259                 DWC_WARN("%s() Buffer size is not a multiple of"
+00260                          "DWORD size (%d)", __func__, bytes);
+00261         }
+00262 
+00263         buf = dma_alloc_coherent(NULL, bytes, dma, gfp_flags);
+00264 
+00265         /* Check dword alignment */
+00266         if (((int)buf & 0x3UL) != 0) {
+00267                 DWC_WARN("%s() Buffer is not DWORD aligned (%p)",
+00268                          __func__, buf);
+00269         }
+00270 
+00271         return buf;
+00272 }
+00273 
+00282 static void dwc_otg_pcd_free_buffer(struct usb_ep *usb_ep, void *buf,
+00283                                     dma_addr_t dma, unsigned bytes)
+00284 {
+00285         dwc_otg_pcd_t *pcd = 0;
+00286 
+00287         pcd = gadget_wrapper->pcd;
+00288 
+00289         DWC_DEBUGPL(DBG_PCDV, "%s(%p,%0x,%d)\n", __func__, buf, dma, bytes);
+00290 
+00291         dma_free_coherent(NULL, bytes, buf, dma);
+00292 }
+00293 
+00308 static int ep_queue(struct usb_ep *usb_ep, struct usb_request *usb_req,
+00309                     gfp_t gfp_flags)
+00310 {
+00311         dwc_otg_pcd_t *pcd;
+00312         int retval;
+00313 
+00314         DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p,%d)\n",
+00315                     __func__, usb_ep, usb_req, gfp_flags);
+00316 
+00317         if (!usb_req || !usb_req->complete || !usb_req->buf) {
+00318                 DWC_WARN("bad params\n");
+00319                 return -EINVAL;
+00320         }
+00321 
+00322         if (!usb_ep) {
+00323                 DWC_WARN("bad ep\n");
+00324                 return -EINVAL;
+00325         }
+00326 
+00327         pcd = gadget_wrapper->pcd;
+00328         if (!gadget_wrapper->driver ||
+00329             gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
+00330                 DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
+00331                             gadget_wrapper->gadget.speed);
+00332                 DWC_WARN("bogus device state\n");
+00333                 return -ESHUTDOWN;
+00334         }
+00335 
+00336         DWC_DEBUGPL(DBG_PCD, "%s queue req %p, len %d buf %p\n",
+00337                     usb_ep->name, usb_req, usb_req->length, usb_req->buf);
+00338 
+00339         usb_req->status = -EINPROGRESS;
+00340         usb_req->actual = 0;
+00341 
+00342         retval = dwc_otg_pcd_ep_queue(pcd, usb_ep, usb_req->buf, usb_req->dma,
+00343                                       usb_req->length, usb_req->zero, usb_req,
+00344                                       gfp_flags == GFP_ATOMIC ? 1 : 0);
+00345         if (retval) {
+00346                 return -EINVAL;
+00347         }
+00348 
+00349         return 0;
+00350 }
+00351 
+00355 static int ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req)
+00356 {
+00357         DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, usb_req);
+00358 
+00359         if (!usb_ep || !usb_req) {
+00360                 DWC_WARN("bad argument\n");
+00361                 return -EINVAL;
+00362         }
+00363         if (!gadget_wrapper->driver ||
+00364             gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
+00365                 DWC_WARN("bogus device state\n");
+00366                 return -ESHUTDOWN;
+00367         }
+00368         if (dwc_otg_pcd_ep_dequeue(gadget_wrapper->pcd, usb_ep, usb_req)) {
+00369                 return -EINVAL;
+00370         }
+00371 
+00372         return 0;
+00373 }
+00374 
+00391 static int ep_halt(struct usb_ep *usb_ep, int value)
+00392 {
+00393         int retval = 0;
+00394 
+00395         DWC_DEBUGPL(DBG_PCD, "HALT %s %d\n", usb_ep->name, value);
+00396 
+00397         if (!usb_ep) {
+00398                 DWC_WARN("bad ep\n");
+00399                 return -EINVAL;
+00400         }
+00401 
+00402         retval = dwc_otg_pcd_ep_halt(gadget_wrapper->pcd, usb_ep, value);
+00403         if (retval == -DWC_E_AGAIN) {
+00404                 return -EAGAIN;
+00405         } else if (retval) {
+00406                 retval = -EINVAL;
+00407         }
+00408 
+00409         return retval;
+00410 }
+00411 
+00412 #ifdef DWC_EN_ISOC
+00413 
+00422 static int iso_ep_start(struct usb_ep *usb_ep, struct usb_iso_request *req,
+00423                         gfp_t gfp_flags)
+00424 {
+00425         int retval = 0;
+00426 
+00427         if (!req || !req->process_buffer || !req->buf0 || !req->buf1) {
+00428                 DWC_WARN("bad params\n");
+00429                 return -EINVAL;
+00430         }
+00431 
+00432         if (!usb_ep) {
+00433                 DWC_PRINTF("bad params\n");
+00434                 return -EINVAL;
+00435         }
+00436 
+00437         req->status = -EINPROGRESS;
+00438 
+00439         retval =
+00440             dwc_otg_pcd_iso_ep_start(gadget_wrapper->pcd, usb_ep, req->buf0,
+00441                                      req->buf1, req->dma0, req->dma1,
+00442                                      req->sync_frame, req->data_pattern_frame,
+00443                                      req->data_per_frame,
+00444                                      req->flags & USB_REQ_ISO_ASAP ? -1 : req->
+00445                                      start_frame, req->buf_proc_intrvl, req,
+00446                                      gfp_flags == GFP_ATOMIC ? 1 : 0);
+00447 
+00448         if (retval) {
+00449                 return -EINVAL;
+00450         }
+00451 
+00452         return retval;
+00453 }
+00454 
+00458 static int iso_ep_stop(struct usb_ep *usb_ep, struct usb_iso_request *req)
+00459 {
+00460         int retval = 0;
+00461         if (!usb_ep) {
+00462                 DWC_WARN("bad ep\n");
+00463         }
+00464 
+00465         if (!gadget_wrapper->driver ||
+00466             gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
+00467                 DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
+00468                             gadget_wrapper->gadget.speed);
+00469                 DWC_WARN("bogus device state\n");
+00470         }
+00471 
+00472         dwc_otg_pcd_iso_ep_stop(gadget_wrapper->pcd, usb_ep, req);
+00473         if (retval) {
+00474                 retval = -EINVAL;
+00475         }
+00476 
+00477         return retval;
+00478 }
+00479 
+00480 static struct usb_iso_request *alloc_iso_request(struct usb_ep *ep,
+00481                                                  int packets, gfp_t gfp_flags)
+00482 {
+00483         struct usb_iso_request *pReq = NULL;
+00484         uint32_t req_size;
+00485 
+00486         req_size = sizeof(struct usb_iso_request);
+00487         req_size +=
+00488             (2 * packets * (sizeof(struct usb_gadget_iso_packet_descriptor)));
+00489 
+00490         pReq = kmalloc(req_size, gfp_flags);
+00491         if (!pReq) {
+00492                 DWC_WARN("Can't allocate Iso Request\n");
+00493                 return 0;
+00494         }
+00495         pReq->iso_packet_desc0 = (void *)(pReq + 1);
+00496 
+00497         pReq->iso_packet_desc1 = pReq->iso_packet_desc0 + packets;
+00498 
+00499         return pReq;
+00500 }
+00501 
+00502 static void free_iso_request(struct usb_ep *ep, struct usb_iso_request *req)
+00503 {
+00504         kfree(req);
+00505 }
+00506 
+00507 static struct usb_isoc_ep_ops dwc_otg_pcd_ep_ops = {
+00508         .ep_ops = {
+00509                    .enable = ep_enable,
+00510                    .disable = ep_disable,
+00511 
+00512                    .alloc_request = dwc_otg_pcd_alloc_request,
+00513                    .free_request = dwc_otg_pcd_free_request,
+00514 
+00515                    .alloc_buffer = dwc_otg_pcd_alloc_buffer,
+00516                    .free_buffer = dwc_otg_pcd_free_buffer,
+00517 
+00518                    .queue = ep_queue,
+00519                    .dequeue = ep_dequeue,
+00520 
+00521                    .set_halt = ep_halt,
+00522                    .fifo_status = 0,
+00523                    .fifo_flush = 0,
+00524                    },
+00525         .iso_ep_start = iso_ep_start,
+00526         .iso_ep_stop = iso_ep_stop,
+00527         .alloc_iso_request = alloc_iso_request,
+00528         .free_iso_request = free_iso_request,
+00529 };
+00530 
+00531 #else
+00532 
+00533 static struct usb_ep_ops dwc_otg_pcd_ep_ops = {
+00534         .enable = ep_enable,
+00535         .disable = ep_disable,
+00536 
+00537         .alloc_request = dwc_otg_pcd_alloc_request,
+00538         .free_request = dwc_otg_pcd_free_request,
+00539 
+00540         .alloc_buffer = dwc_otg_pcd_alloc_buffer,
+00541         .free_buffer = dwc_otg_pcd_free_buffer,
+00542 
+00543         .queue = ep_queue,
+00544         .dequeue = ep_dequeue,
+00545 
+00546         .set_halt = ep_halt,
+00547         .fifo_status = 0,
+00548         .fifo_flush = 0,
+00549 
+00550 };
+00551 
+00552 #endif                          /* _EN_ISOC_ */
+00553 /*      Gadget Operations */
+00572 static int get_frame_number(struct usb_gadget *gadget)
+00573 {
+00574         struct gadget_wrapper *d;
+00575 
+00576         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
+00577 
+00578         if (gadget == 0) {
+00579                 return -ENODEV;
+00580         }
+00581 
+00582         d = container_of(gadget, struct gadget_wrapper, gadget);
+00583         return dwc_otg_pcd_get_frame_number(d->pcd);
+00584 }
+00585 
+00586 #ifdef CONFIG_USB_DWC_OTG_LPM
+00587 static int test_lpm_enabled(struct usb_gadget *gadget)
+00588 {
+00589         struct gadget_wrapper *d;
+00590 
+00591         d = container_of(gadget, struct gadget_wrapper, gadget);
+00592 
+00593         return dwc_otg_pcd_is_lpm_enabled(d->pcd);
+00594 }
+00595 #endif
+00596 
+00603 static int wakeup(struct usb_gadget *gadget)
+00604 {
+00605         struct gadget_wrapper *d;
+00606 
+00607         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);
+00608 
+00609         if (gadget == 0) {
+00610                 return -ENODEV;
+00611         } else {
+00612                 d = container_of(gadget, struct gadget_wrapper, gadget);
+00613         }
+00614         dwc_otg_pcd_wakeup(d->pcd);
+00615         return 0;
+00616 }
+00617 
+00618 static const struct usb_gadget_ops dwc_otg_pcd_ops = {
+00619         .get_frame = get_frame_number,
+00620         .wakeup = wakeup,
+00621 #ifdef CONFIG_USB_DWC_OTG_LPM
+00622         .lpm_support = test_lpm_enabled,
+00623 #endif
+00624         // current versions must always be self-powered
+00625 };
+00626 
+00627 static int _setup(dwc_otg_pcd_t * pcd, uint8_t * bytes)
+00628 {
+00629         int retval = -DWC_E_NOT_SUPPORTED;
+00630         if (gadget_wrapper->driver && gadget_wrapper->driver->setup) {
+00631                 retval = gadget_wrapper->driver->setup(&gadget_wrapper->gadget,
+00632                                                        (struct usb_ctrlrequest
+00633                                                         *)bytes);
+00634         }
+00635 
+00636         if (retval == -ENOTSUPP) {
+00637                 retval = -DWC_E_NOT_SUPPORTED;
+00638         } else if (retval < 0) {
+00639                 retval = -DWC_E_INVALID;
+00640         }
+00641 
+00642         return retval;
+00643 }
+00644 
+00645 #ifdef DWC_EN_ISOC
+00646 static int _isoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
+00647                           void *req_handle, int proc_buf_num)
+00648 {
+00649         int i, packet_count;
+00650         struct usb_gadget_iso_packet_descriptor *iso_packet = 0;
+00651         struct usb_iso_request *iso_req = req_handle;
+00652 
+00653         if (proc_buf_num) {
+00654                 iso_packet = iso_req->iso_packet_desc1;
+00655         } else {
+00656                 iso_packet = iso_req->iso_packet_desc0;
+00657         }
+00658         packet_count =
+00659             dwc_otg_pcd_get_iso_packet_count(pcd, ep_handle, req_handle);
+00660         for (i = 0; i < packet_count; ++i) {
+00661                 int status;
+00662                 int actual;
+00663                 int offset;
+00664                 dwc_otg_pcd_get_iso_packet_params(pcd, ep_handle, req_handle,
+00665                                                   i, &status, &actual, &offset);
+00666                 switch (status) {
+00667                 case -DWC_E_NO_DATA:
+00668                         status = -ENODATA;
+00669                         break;
+00670                 default:
+00671                         if (status) {
+00672                                 DWC_PRINTF("unknown status in isoc packet\n");
+00673                         }
+00674 
+00675                 }
+00676                 iso_packet[i].status = status;
+00677                 iso_packet[i].offset = offset;
+00678                 iso_packet[i].actual_length = actual;
+00679         }
+00680 
+00681         iso_req->status = 0;
+00682         iso_req->process_buffer(ep_handle, iso_req);
+00683 
+00684         return 0;
+00685 }
+00686 #endif                          /* DWC_EN_ISOC */
+00687 
+00688 static int _complete(dwc_otg_pcd_t * pcd, void *ep_handle,
+00689                      void *req_handle, int32_t status, uint32_t actual)
+00690 {
+00691         struct usb_request *req = (struct usb_request *)req_handle;
+00692 
+00693         if (req && req->complete) {
+00694                 switch (status) {
+00695                 case -DWC_E_SHUTDOWN:
+00696                         req->status = -ESHUTDOWN;
+00697                         break;
+00698                 case -DWC_E_RESTART:
+00699                         req->status = -ECONNRESET;
+00700                         break;
+00701                 case -DWC_E_INVALID:
+00702                         req->status = -EINVAL;
+00703                         break;
+00704                 case -DWC_E_TIMEOUT:
+00705                         req->status = -ETIMEDOUT;
+00706                         break;
+00707                 default:
+00708                         req->status = status;
+00709 
+00710                 }
+00711                 req->actual = actual;
+00712                 req->complete(ep_handle, req);
+00713         }
+00714 
+00715         return 0;
+00716 }
+00717 
+00718 static int _connect(dwc_otg_pcd_t * pcd, int speed)
+00719 {
+00720         gadget_wrapper->gadget.speed = speed;
+00721         return 0;
+00722 }
+00723 
+00724 static int _disconnect(dwc_otg_pcd_t * pcd)
+00725 {
+00726         if (gadget_wrapper->driver && gadget_wrapper->driver->disconnect) {
+00727                 gadget_wrapper->driver->disconnect(&gadget_wrapper->gadget);
+00728         }
+00729         return 0;
+00730 }
+00731 
+00732 static int _resume(dwc_otg_pcd_t * pcd)
+00733 {
+00734         if (gadget_wrapper->driver && gadget_wrapper->driver->resume) {
+00735                 gadget_wrapper->driver->resume(&gadget_wrapper->gadget);
+00736         }
+00737 
+00738         return 0;
+00739 }
+00740 
+00741 static int _suspend(dwc_otg_pcd_t * pcd)
+00742 {
+00743         if (gadget_wrapper->driver && gadget_wrapper->driver->suspend) {
+00744                 gadget_wrapper->driver->suspend(&gadget_wrapper->gadget);
+00745         }
+00746         return 0;
+00747 }
+00748 
+00752 static int _hnp_changed(dwc_otg_pcd_t * pcd)
+00753 {
+00754 
+00755         if (!gadget_wrapper->gadget.is_otg)
+00756                 return 0;
+00757 
+00758         gadget_wrapper->gadget.b_hnp_enable = get_b_hnp_enable(pcd);
+00759         gadget_wrapper->gadget.a_hnp_support = get_a_hnp_support(pcd);
+00760         gadget_wrapper->gadget.a_alt_hnp_support = get_a_alt_hnp_support(pcd);
+00761         return 0;
+00762 }
+00763 
+00764 static int _reset(dwc_otg_pcd_t * pcd)
+00765 {
+00766         return 0;
+00767 }
+00768 
+00769 #ifdef DWC_UTE_CFI
+00770 static int _cfi_setup(dwc_otg_pcd_t * pcd, void *cfi_req)
+00771 {
+00772         int retval = -DWC_E_INVALID;
+00773         if (gadget_wrapper->driver->cfi_feature_setup) {
+00774                 retval =
+00775                     gadget_wrapper->driver->cfi_feature_setup(&gadget_wrapper->
+00776                                                               gadget,
+00777                                                               (struct
+00778                                                                cfi_usb_ctrlrequest
+00779                                                                *)cfi_req);
+00780         }
+00781 
+00782         return retval;
+00783 }
+00784 #endif
+00785 
+00786 static const struct dwc_otg_pcd_function_ops fops = {
+00787         .complete = _complete,
+00788 #ifdef DWC_EN_ISOC
+00789         .isoc_complete = _isoc_complete,
+00790 #endif
+00791         .setup = _setup,
+00792         .disconnect = _disconnect,
+00793         .connect = _connect,
+00794         .resume = _resume,
+00795         .suspend = _suspend,
+00796         .hnp_changed = _hnp_changed,
+00797         .reset = _reset,
+00798 #ifdef DWC_UTE_CFI
+00799         .cfi_setup = _cfi_setup,
+00800 #endif
+00801 };
+00802 
+00806 static irqreturn_t dwc_otg_pcd_irq(int irq, void *dev)
+00807 {
+00808         dwc_otg_pcd_t *pcd = dev;
+00809         int32_t retval = IRQ_NONE;
+00810 
+00811         retval = dwc_otg_pcd_handle_intr(pcd);
+00812         if (retval != 0) {
+00813                 S3C2410X_CLEAR_EINTPEND();
+00814         }
+00815         return IRQ_RETVAL(retval);
+00816 }
+00817 
+00824 void gadget_add_eps(struct gadget_wrapper *d)
+00825 {
+00826         static const char *names[] = {
+00827 
+00828                 "ep0",
+00829                 "ep1in",
+00830                 "ep2in",
+00831                 "ep3in",
+00832                 "ep4in",
+00833                 "ep5in",
+00834                 "ep6in",
+00835                 "ep7in",
+00836                 "ep8in",
+00837                 "ep9in",
+00838                 "ep10in",
+00839                 "ep11in",
+00840                 "ep12in",
+00841                 "ep13in",
+00842                 "ep14in",
+00843                 "ep15in",
+00844                 "ep1out",
+00845                 "ep2out",
+00846                 "ep3out",
+00847                 "ep4out",
+00848                 "ep5out",
+00849                 "ep6out",
+00850                 "ep7out",
+00851                 "ep8out",
+00852                 "ep9out",
+00853                 "ep10out",
+00854                 "ep11out",
+00855                 "ep12out",
+00856                 "ep13out",
+00857                 "ep14out",
+00858                 "ep15out"
+00859         };
+00860 
+00861         int i;
+00862         struct usb_ep *ep;
+00863 
+00864         DWC_DEBUGPL(DBG_PCDV, "%s\n", __func__);
+00865 
+00866         INIT_LIST_HEAD(&d->gadget.ep_list);
+00867         d->gadget.ep0 = &d->ep0;
+00868         d->gadget.speed = USB_SPEED_UNKNOWN;
+00869 
+00870         INIT_LIST_HEAD(&d->gadget.ep0->ep_list);
+00871 
+00875         ep = &d->ep0;
+00876 
+00877         /* Init the usb_ep structure. */
+00878         ep->name = names[0];
+00879         ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
+00880 
+00885         ep->maxpacket = MAX_PACKET_SIZE;
+00886         dwc_otg_pcd_ep_enable(d->pcd, NULL, ep);
+00887 
+00888         list_add_tail(&ep->ep_list, &d->gadget.ep_list);
+00889 
+00894         for (i = 0; i < 15; i++) {
+00895                 ep = &d->in_ep[i];
+00896 
+00897                 /* Init the usb_ep structure. */
+00898                 ep->name = names[i + 1];
+00899                 ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
+00900 
+00905                 ep->maxpacket = MAX_PACKET_SIZE;
+00906                 list_add_tail(&ep->ep_list, &d->gadget.ep_list);
+00907         }
+00908 
+00909         for (i = 0; i < 15; i++) {
+00910                 ep = &d->out_ep[i];
+00911 
+00912                 /* Init the usb_ep structure. */
+00913                 ep->name = names[15 + i + 1];
+00914                 ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;
+00915 
+00920                 ep->maxpacket = MAX_PACKET_SIZE;
+00921 
+00922                 list_add_tail(&ep->ep_list, &d->gadget.ep_list);
+00923         }
+00924 
+00925         /* remove ep0 from the list.  There is a ep0 pointer. */
+00926         list_del_init(&d->ep0.ep_list);
+00927 
+00928         d->ep0.maxpacket = MAX_EP0_SIZE;
+00929 }
+00930 
+00937 static void dwc_otg_pcd_gadget_release(struct device *dev)
+00938 {
+00939         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, dev);
+00940 }
+00941 
+00942 static struct gadget_wrapper *alloc_wrapper(
+00943 #ifdef LM_INTERFACE
+00944         struct lm_device *_dev
+00945 #elif  PCI_INTERFACE
+00946         struct pci_dev *_dev
+00947 #endif
+00948         )
+00949 {
+00950         static char pcd_name[] = "dwc_otg_pcd";
+00951 #ifdef LM_INTERFACE
+00952         dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
+00953 #elif PCI_INTERFACE
+00954         dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
+00955 #endif
+00956 
+00957         struct gadget_wrapper *d;
+00958         int retval;
+00959 
+00960         d = dwc_alloc(sizeof(*d));
+00961         if (d == NULL) {
+00962                 return NULL;
+00963         }
+00964 
+00965         memset(d, 0, sizeof(*d));
+00966 
+00967         d->gadget.name = pcd_name;
+00968         d->pcd = otg_dev->pcd;
+00969         strcpy(d->gadget.dev.bus_id, "gadget");
+00970 
+00971         d->gadget.dev.parent = &_dev->dev;
+00972         d->gadget.dev.release = dwc_otg_pcd_gadget_release;
+00973         d->gadget.ops = &dwc_otg_pcd_ops;
+00974         d->gadget.is_dualspeed = dwc_otg_pcd_is_dualspeed(otg_dev->pcd);
+00975         d->gadget.is_otg = dwc_otg_pcd_is_otg(otg_dev->pcd);
+00976 
+00977         d->driver = 0;
+00978         /* Register the gadget device */
+00979         retval = device_register(&d->gadget.dev);
+00980         if (retval != 0) {
+00981                 DWC_ERROR("device_register failed\n");
+00982                 dwc_free(d);
+00983                 return NULL;
+00984         }
+00985 
+00986         return d;
+00987 }
+00988 
+00989 static void free_wrapper(struct gadget_wrapper *d)
+00990 {
+00991         if (d->driver) {
+00992                 /* should have been done already by driver model core */
+00993                 DWC_WARN("driver '%s' is still registered\n",
+00994                          d->driver->driver.name);
+00995                 usb_gadget_unregister_driver(d->driver);
+00996         }
+00997 
+00998         device_unregister(&d->gadget.dev);
+00999         dwc_free(d);
+01000 }
+01001 
+01006 int pcd_init(
+01007 #ifdef LM_INTERFACE
+01008         struct lm_device *_dev
+01009 #elif  PCI_INTERFACE
+01010         struct pci_dev *_dev
+01011 #endif
+01012         )
+01013 
+01014 {
+01015 #ifdef LM_INTERFACE
+01016         dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
+01017 #elif  PCI_INTERFACE
+01018         dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
+01019 #endif
+01020 
+01021         int retval = 0;
+01022 
+01023         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _dev);
+01024 
+01025         otg_dev->pcd = dwc_otg_pcd_init(otg_dev->core_if);
+01026 
+01027         if (!otg_dev->pcd) {
+01028                 DWC_ERROR("dwc_otg_pcd_init failed\n");
+01029                 return -ENOMEM;
+01030         }
+01031 
+01032         gadget_wrapper = alloc_wrapper(_dev);
+01033 
+01034         /*
+01035          * Initialize EP structures
+01036          */
+01037         gadget_add_eps(gadget_wrapper);
+01038 
+01039         /*
+01040          * Setup interupt handler
+01041          */
+01042         DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n", _dev->irq);
+01043         retval = request_irq(_dev->irq, dwc_otg_pcd_irq,
+01044                              SA_SHIRQ, gadget_wrapper->gadget.name,
+01045                              otg_dev->pcd);
+01046         if (retval != 0) {
+01047                 DWC_ERROR("request of irq%d failed\n", _dev->irq);
+01048                 free_wrapper(gadget_wrapper);
+01049                 return -EBUSY;
+01050         }
+01051 
+01052         dwc_otg_pcd_start(gadget_wrapper->pcd, &fops);
+01053 
+01054         return retval;
+01055 }
+01056 
+01060 void pcd_remove(
+01061 #ifdef LM_INTERFACE
+01062         struct lm_device *_dev
+01063 #elif  PCI_INTERFACE
+01064         struct pci_dev *_dev
+01065 #endif
+01066         )
+01067 {
+01068 #ifdef LM_INTERFACE
+01069         dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev);
+01070 #elif  PCI_INTERFACE
+01071         dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
+01072 #endif
+01073         dwc_otg_pcd_t *pcd = otg_dev->pcd;
+01074 
+01075         DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _dev);
+01076 
+01077         /*
+01078          * Free the IRQ
+01079          */
+01080         free_irq(_dev->irq, pcd);
+01081         dwc_otg_pcd_remove(otg_dev->pcd);
+01082         free_wrapper(gadget_wrapper);
+01083         otg_dev->pcd = 0;
+01084 }
+01085 
+01096 int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+01097 {
+01098         int retval;
+01099 
+01100         DWC_DEBUGPL(DBG_PCD, "registering gadget driver '%s'\n",
+01101                     driver->driver.name);
+01102 
+01103         if (!driver || driver->speed == USB_SPEED_UNKNOWN ||
+01104             !driver->bind ||
+01105             !driver->unbind || !driver->disconnect || !driver->setup) {
+01106                 DWC_DEBUGPL(DBG_PCDV, "EINVAL\n");
+01107                 return -EINVAL;
+01108         }
+01109         if (gadget_wrapper == 0) {
+01110                 DWC_DEBUGPL(DBG_PCDV, "ENODEV\n");
+01111                 return -ENODEV;
+01112         }
+01113         if (gadget_wrapper->driver != 0) {
+01114                 DWC_DEBUGPL(DBG_PCDV, "EBUSY (%p)\n", gadget_wrapper->driver);
+01115                 return -EBUSY;
+01116         }
+01117 
+01118         /* hook up the driver */
+01119         gadget_wrapper->driver = driver;
+01120         gadget_wrapper->gadget.dev.driver = &driver->driver;
+01121 
+01122         DWC_DEBUGPL(DBG_PCD, "bind to driver %s\n", driver->driver.name);
+01123         retval = driver->bind(&gadget_wrapper->gadget);
+01124         if (retval) {
+01125                 DWC_ERROR("bind to driver %s --> error %d\n",
+01126                           driver->driver.name, retval);
+01127                 gadget_wrapper->driver = 0;
+01128                 gadget_wrapper->gadget.dev.driver = 0;
+01129                 return retval;
+01130         }
+01131         DWC_DEBUGPL(DBG_ANY, "registered gadget driver '%s'\n",
+01132                     driver->driver.name);
+01133         return 0;
+01134 }
+01135 
+01136 EXPORT_SYMBOL(usb_gadget_register_driver);
+01137 
+01143 int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+01144 {
+01145         //DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _driver);
+01146 
+01147         if (gadget_wrapper == 0) {
+01148                 DWC_DEBUGPL(DBG_ANY, "%s Return(%d): s_pcd==0\n", __func__,
+01149                             -ENODEV);
+01150                 return -ENODEV;
+01151         }
+01152         if (driver == 0 || driver != gadget_wrapper->driver) {
+01153                 DWC_DEBUGPL(DBG_ANY, "%s Return(%d): driver?\n", __func__,
+01154                             -EINVAL);
+01155                 return -EINVAL;
+01156         }
+01157 
+01158         driver->unbind(&gadget_wrapper->gadget);
+01159         gadget_wrapper->driver = 0;
+01160 
+01161         DWC_DEBUGPL(DBG_ANY, "unregistered driver '%s'\n", driver->driver.name);
+01162         return 0;
+01163 }
+01164 
+01165 EXPORT_SYMBOL(usb_gadget_unregister_driver);
+01166 
+01167 #endif                          /* DWC_HOST_ONLY */
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__linux_8c.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__linux_8c.html new file mode 100644 index 000000000000..26ee9dffb0ee --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__pcd__linux_8c.html @@ -0,0 +1,796 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_pcd_linux.c File Reference + + + + + + +

dwc_otg_pcd_linux.c File Reference

This file implements the Peripheral Controller Driver. More... +

+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/dma-mapping.h>
+#include <linux/version.h>
+#include <asm/io.h>
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+#include "dwc_otg_pcd_if.h"
+#include "dwc_otg_driver.h"
+#include "dwc_otg_dbg.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Structures

struct  gadget_wrapper

Functions

+void dump_msg (const u8 *buf, unsigned int length)
static int ep_enable (struct usb_ep *usb_ep, const struct usb_endpoint_descriptor *ep_desc)
 This function is called by the Gadget Driver for each EP to be configured for the current configuration (SET_CONFIGURATION).
static int ep_disable (struct usb_ep *usb_ep)
 This function is called when an EP is disabled due to disconnect or change in configuration.
static struct usb_request * dwc_otg_pcd_alloc_request (struct usb_ep *ep, gfp_t gfp_flags)
 This function allocates a request object to use with the specified endpoint.
static void dwc_otg_pcd_free_request (struct usb_ep *ep, struct usb_request *req)
 This function frees a request object.
static void * dwc_otg_pcd_alloc_buffer (struct usb_ep *usb_ep, unsigned bytes, dma_addr_t *dma, gfp_t gfp_flags)
 This function allocates an I/O buffer to be used for a transfer to/from the specified endpoint.
static void dwc_otg_pcd_free_buffer (struct usb_ep *usb_ep, void *buf, dma_addr_t dma, unsigned bytes)
 This function frees an I/O buffer that was allocated by alloc_buffer.
static int ep_queue (struct usb_ep *usb_ep, struct usb_request *usb_req, gfp_t gfp_flags)
 This function is used to submit an I/O Request to an EP.
+static int ep_dequeue (struct usb_ep *usb_ep, struct usb_request *usb_req)
 This function cancels an I/O request from an EP.
static int ep_halt (struct usb_ep *usb_ep, int value)
 usb_ep_set_halt stalls an endpoint.
static int iso_ep_start (struct usb_ep *usb_ep, struct usb_iso_request *req, gfp_t gfp_flags)
 This function is used to submit an ISOC Transfer Request to an EP.
+static int iso_ep_stop (struct usb_ep *usb_ep, struct usb_iso_request *req)
 This function stops ISO EP Periodic Data Transfer.
+static struct usb_iso_request * alloc_iso_request (struct usb_ep *ep, int packets, gfp_t gfp_flags)
+static void free_iso_request (struct usb_ep *ep, struct usb_iso_request *req)
+static int get_frame_number (struct usb_gadget *gadget)
 Gets the USB Frame number of the last SOF.
static int wakeup (struct usb_gadget *gadget)
 Initiates Session Request Protocol (SRP) to wakeup the host if no session is in progress.
+static int _setup (dwc_otg_pcd_t *pcd, uint8_t *bytes)
+static int _isoc_complete (dwc_otg_pcd_t *pcd, void *ep_handle, void *req_handle, int proc_buf_num)
+static int _complete (dwc_otg_pcd_t *pcd, void *ep_handle, void *req_handle, int32_t status, uint32_t actual)
+static int _connect (dwc_otg_pcd_t *pcd, int speed)
+static int _disconnect (dwc_otg_pcd_t *pcd)
+static int _resume (dwc_otg_pcd_t *pcd)
+static int _suspend (dwc_otg_pcd_t *pcd)
+static int _hnp_changed (dwc_otg_pcd_t *pcd)
 This function updates the otg values in the gadget structure.
+static int _reset (dwc_otg_pcd_t *pcd)
+static irqreturn_t dwc_otg_pcd_irq (int irq, void *dev)
 This function is the top level PCD interrupt handler.
void gadget_add_eps (struct gadget_wrapper *d)
 This function initialized the usb_ep structures to there default state.
static void dwc_otg_pcd_gadget_release (struct device *dev)
 This function releases the Gadget device.
+static struct gadget_wrapperalloc_wrapper ()
+static void free_wrapper (struct gadget_wrapper *d)
+int pcd_init ()
 This function initialized the PCD portion of the driver.
+void pcd_remove ()
 Cleanup the PCD.
int usb_gadget_register_driver (struct usb_gadget_driver *driver)
 This function registers a gadget driver with the PCD.
EXPORT_SYMBOL (usb_gadget_register_driver)
int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 This function unregisters a gadget driver.
EXPORT_SYMBOL (usb_gadget_unregister_driver)

Variables

static struct usb_isoc_ep_ops dwc_otg_pcd_ep_ops
static struct usb_gadget_ops dwc_otg_pcd_ops
static struct dwc_otg_pcd_function_ops fops
+


Detailed Description

+This file implements the Peripheral Controller Driver. +

+The Peripheral Controller Driver (PCD) is responsible for translating requests from the Function Driver into the appropriate actions on the DWC_otg controller. It isolates the Function Driver from the specifics of the controller by providing an API to the Function Driver.

+The Peripheral Controller Driver for Linux will implement the Gadget API, so that the existing Gadget drivers can be used. (Gadget Driver is the Linux terminology for a Function Driver.)

+The Linux Gadget API is defined in the header file <linux/usb_gadget.h>. The USB EP operations API is defined in the structure usb_ep_ops and the USB Controller API is defined in the structure usb_gadget_ops. +

+Definition in file dwc_otg_pcd_linux.c.


Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
static int ep_enable (struct usb_ep *  usb_ep,
const struct usb_endpoint_descriptor *  ep_desc 
) [static]
+
+
+ +

+This function is called by the Gadget Driver for each EP to be configured for the current configuration (SET_CONFIGURATION). +

+This function initializes the dwc_otg_ep_t data structure, and then calls dwc_otg_ep_activate. +

+Definition at line 121 of file dwc_otg_pcd_linux.c. +

+

+ +

+
+ + + + + + + + + +
static int ep_disable (struct usb_ep *  usb_ep  )  [static]
+
+
+ +

+This function is called when an EP is disabled due to disconnect or change in configuration. +

+Any pending requests will terminate with a status of -ESHUTDOWN.

+This function modifies the dwc_otg_ep_t data structure for this EP, and then calls dwc_otg_ep_deactivate. +

+Definition at line 170 of file dwc_otg_pcd_linux.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static struct usb_request* dwc_otg_pcd_alloc_request (struct usb_ep *  ep,
gfp_t  gfp_flags 
) [static]
+
+
+ +

+This function allocates a request object to use with the specified endpoint. +

+

Parameters:
+ + + +
ep The endpoint to be used with with the request
gfp_flags the GFP_* flags to use.
+
+ +

+Definition at line 196 of file dwc_otg_pcd_linux.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static void dwc_otg_pcd_free_request (struct usb_ep *  ep,
struct usb_request *  req 
) [static]
+
+
+ +

+This function frees a request object. +

+

Parameters:
+ + + +
ep The endpoint associated with the request
req The request being freed
+
+ +

+Definition at line 223 of file dwc_otg_pcd_linux.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static void* dwc_otg_pcd_alloc_buffer (struct usb_ep *  usb_ep,
unsigned  bytes,
dma_addr_t *  dma,
gfp_t  gfp_flags 
) [static]
+
+
+ +

+This function allocates an I/O buffer to be used for a transfer to/from the specified endpoint. +

+

Parameters:
+ + + + + +
usb_ep The endpoint to be used with with the request
bytes The desired number of bytes for the buffer
dma Pointer to the buffer's DMA address; must be valid
gfp_flags the GFP_* flags to use.
+
+
Returns:
address of a new buffer or null is buffer could not be allocated.
+ +

+Definition at line 246 of file dwc_otg_pcd_linux.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static void dwc_otg_pcd_free_buffer (struct usb_ep *  usb_ep,
void *  buf,
dma_addr_t  dma,
unsigned  bytes 
) [static]
+
+
+ +

+This function frees an I/O buffer that was allocated by alloc_buffer. +

+

Parameters:
+ + + + + +
usb_ep the endpoint associated with the buffer
buf address of the buffer
dma The buffer's DMA address
bytes The number of bytes of the buffer
+
+ +

+Definition at line 282 of file dwc_otg_pcd_linux.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
static int ep_queue (struct usb_ep *  usb_ep,
struct usb_request *  usb_req,
gfp_t  gfp_flags 
) [static]
+
+
+ +

+This function is used to submit an I/O Request to an EP. +

+

    +
  • When the request completes the request's completion callback is called to return the request to the driver.
  • An EP, except control EPs, may have multiple requests pending.
  • Once submitted the request cannot be examined or modified.
  • Each request is turned into one or more packets.
  • A BULK EP can queue any amount of data; the transfer is packetized.
  • Zero length Packets are specified with the request 'zero' flag.
+ +

+Definition at line 308 of file dwc_otg_pcd_linux.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + +
static int ep_halt (struct usb_ep *  usb_ep,
int  value 
) [static]
+
+
+ +

+usb_ep_set_halt stalls an endpoint. +

+usb_ep_clear_halt clears an endpoint halt and resets its data toggle.

+Both of these functions are implemented with the same underlying function. The behavior depends on the value argument.

+

Parameters:
+ + + +
[in] usb_ep the Endpoint to halt or clear halt.
[in] value 
    +
  • 0 means clear_halt.
  • 1 means set_halt,
  • 2 means clear stall lock flag.
  • 3 means set stall lock flag.
+
+
+ +

+Definition at line 391 of file dwc_otg_pcd_linux.c. +

+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
static int iso_ep_start (struct usb_ep *  usb_ep,
struct usb_iso_request *  req,
gfp_t  gfp_flags 
) [static]
+
+
+ +

+This function is used to submit an ISOC Transfer Request to an EP. +

+

    +
  • Every time a sync period completes the request's completion callback is called to provide data to the gadget driver.
  • Once submitted the request cannot be modified.
  • Each request is turned into periodic data packets untill ISO Transfer is stopped..
+ +

+Definition at line 422 of file dwc_otg_pcd_linux.c. +

+

+ +

+
+ + + + + + + + + +
static int wakeup (struct usb_gadget *  gadget  )  [static]
+
+
+ +

+Initiates Session Request Protocol (SRP) to wakeup the host if no session is in progress. +

+If a session is already in progress, but the device is suspended, remote wakeup signaling is started. +

+Definition at line 603 of file dwc_otg_pcd_linux.c. +

+

+ +

+
+ + + + + + + + + +
void gadget_add_eps (struct gadget_wrapper d  ) 
+
+
+ +

+This function initialized the usb_ep structures to there default state. +

+

Parameters:
+ + +
d Pointer on gadget_wrapper.
+
+ +

+Initialize the EP0 structure.

+

Todo:
NGS: What should the max packet size be set to here? Before EP type is set?
+

+Initialize the EP structures.

+

Todo:
NGS: What should the max packet size be set to here? Before EP type is set?
+

+

Todo:
NGS: What should the max packet size be set to here? Before EP type is set?
+ +

+Definition at line 824 of file dwc_otg_pcd_linux.c. +

+

+ +

+
+ + + + + + + + + +
static void dwc_otg_pcd_gadget_release (struct device *  dev  )  [static]
+
+
+ +

+This function releases the Gadget device. +

+required by device_unregister().

+

Todo:
Should this do something? Should it free the PCD?
+ +

+Definition at line 937 of file dwc_otg_pcd_linux.c. +

+

+ +

+
+ + + + + + + + + +
int usb_gadget_register_driver (struct usb_gadget_driver *  driver  ) 
+
+
+ +

+This function registers a gadget driver with the PCD. +

+When a driver is successfully registered, it will receive control requests including set_configuration(), which enables non-control requests. then usb traffic follows until a disconnect is reported. then a host may connect again, or the driver might get unbound.

+

Parameters:
+ + +
driver The driver being registered
+
+ +

+Definition at line 1096 of file dwc_otg_pcd_linux.c. +

+

+ +

+
+ + + + + + + + + +
int usb_gadget_unregister_driver (struct usb_gadget_driver *  driver  ) 
+
+
+ +

+This function unregisters a gadget driver. +

+

Parameters:
+ + +
driver The driver being unregistered
+
+ +

+Definition at line 1143 of file dwc_otg_pcd_linux.c. +

+

+


Variable Documentation

+ +
+
+ + + + +
struct usb_isoc_ep_ops dwc_otg_pcd_ep_ops [static]
+
+
+ +

+Initial value:

 {
+        .ep_ops = {
+                   .enable = ep_enable,
+                   .disable = ep_disable,
+
+                   .alloc_request = dwc_otg_pcd_alloc_request,
+                   .free_request = dwc_otg_pcd_free_request,
+
+                   .alloc_buffer = dwc_otg_pcd_alloc_buffer,
+                   .free_buffer = dwc_otg_pcd_free_buffer,
+
+                   .queue = ep_queue,
+                   .dequeue = ep_dequeue,
+
+                   .set_halt = ep_halt,
+                   .fifo_status = 0,
+                   .fifo_flush = 0,
+                   },
+        .iso_ep_start = iso_ep_start,
+        .iso_ep_stop = iso_ep_stop,
+        .alloc_iso_request = alloc_iso_request,
+        .free_iso_request = free_iso_request,
+}
+
+

+Definition at line 507 of file dwc_otg_pcd_linux.c. +

+

+ +

+
+ + + + +
struct usb_gadget_ops dwc_otg_pcd_ops [static]
+
+
+ +

+Initial value:

 {
+        .get_frame = get_frame_number,
+        .wakeup = wakeup,
+
+
+
+        
+}
+
+

+Definition at line 618 of file dwc_otg_pcd_linux.c. +

+

+ +

+
+ + + + +
struct dwc_otg_pcd_function_ops fops [static]
+
+
+ +

+Initial value:

 {
+        .complete = _complete,
+
+        .isoc_complete = _isoc_complete,
+
+        .setup = _setup,
+        .disconnect = _disconnect,
+        .connect = _connect,
+        .resume = _resume,
+        .suspend = _suspend,
+        .hnp_changed = _hnp_changed,
+        .reset = _reset,
+
+
+
+}
+
+

+Definition at line 786 of file dwc_otg_pcd_linux.c. +

+

+


Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__regs_8h-source.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__regs_8h-source.html new file mode 100644 index 000000000000..6efa7f867a1b --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__regs_8h-source.html @@ -0,0 +1,1260 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_regs.h Source File + + + + + + +

dwc_otg_regs.h

Go to the documentation of this file.
00001 /* ==========================================================================
+00002  * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_regs.h $
+00003  * $Revision: #76 $
+00004  * $Date: 2009/04/02 $
+00005  * $Change: 1224216 $
+00006  *
+00007  * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+00008  * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+00009  * otherwise expressly agreed to in writing between Synopsys and you.
+00010  * 
+00011  * The Software IS NOT an item of Licensed Software or Licensed Product under
+00012  * any End User Software License Agreement or Agreement for Licensed Product
+00013  * with Synopsys or any supplement thereto. You are permitted to use and
+00014  * redistribute this Software in source and binary forms, with or without
+00015  * modification, provided that redistributions of source code must retain this
+00016  * notice. You may not view, use, disclose, copy or distribute this file or
+00017  * any information contained herein except pursuant to this license grant from
+00018  * Synopsys. If you do not agree with this notice, including the disclaimer
+00019  * below, then you are not authorized to use the Software.
+00020  * 
+00021  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+00023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+00024  * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+00025  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+00027  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+00028  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+00029  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+00030  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+00031  * DAMAGE.
+00032  * ========================================================================== */
+00033 
+00034 #ifndef __DWC_OTG_REGS_H__
+00035 #define __DWC_OTG_REGS_H__
+00036 
+00037 #include "dwc_otg_core_if.h"
+00038 
+00066 /****************************************************************************/
+00071 typedef struct dwc_otg_core_global_regs {
+00073         volatile uint32_t gotgctl;
+00075         volatile uint32_t gotgint;
+00077         volatile uint32_t gahbcfg;
+00078 
+00079 #define DWC_GLBINTRMASK         0x0001
+00080 #define DWC_DMAENABLE           0x0020
+00081 #define DWC_NPTXEMPTYLVL_EMPTY  0x0080
+00082 #define DWC_NPTXEMPTYLVL_HALFEMPTY      0x0000
+00083 #define DWC_PTXEMPTYLVL_EMPTY   0x0100
+00084 #define DWC_PTXEMPTYLVL_HALFEMPTY       0x0000
+00085 
+00087         volatile uint32_t gusbcfg;
+00089         volatile uint32_t grstctl;
+00091         volatile uint32_t gintsts;
+00093         volatile uint32_t gintmsk;
+00095         volatile uint32_t grxstsr;
+00097         volatile uint32_t grxstsp;
+00099         volatile uint32_t grxfsiz;
+00101         volatile uint32_t gnptxfsiz;
+00104         volatile uint32_t gnptxsts;
+00106         volatile uint32_t gi2cctl;
+00108         volatile uint32_t gpvndctl;
+00110         volatile uint32_t ggpio;
+00112         volatile uint32_t guid;
+00114         volatile uint32_t gsnpsid;
+00116         volatile uint32_t ghwcfg1;
+00118         volatile uint32_t ghwcfg2;
+00119 #define DWC_SLAVE_ONLY_ARCH 0
+00120 #define DWC_EXT_DMA_ARCH 1
+00121 #define DWC_INT_DMA_ARCH 2
+00122 
+00123 #define DWC_MODE_HNP_SRP_CAPABLE        0
+00124 #define DWC_MODE_SRP_ONLY_CAPABLE       1
+00125 #define DWC_MODE_NO_HNP_SRP_CAPABLE             2
+00126 #define DWC_MODE_SRP_CAPABLE_DEVICE             3
+00127 #define DWC_MODE_NO_SRP_CAPABLE_DEVICE  4
+00128 #define DWC_MODE_SRP_CAPABLE_HOST       5
+00129 #define DWC_MODE_NO_SRP_CAPABLE_HOST    6
+00130 
+00132         volatile uint32_t ghwcfg3;
+00134         volatile uint32_t ghwcfg4;
+00136         volatile uint32_t glpmcfg;
+00138         volatile uint32_t reserved[42];
+00140         volatile uint32_t hptxfsiz;
+00144         volatile uint32_t dptxfsiz_dieptxf[15];
+00145 } dwc_otg_core_global_regs_t;
+00146 
+00152 typedef union gotgctl_data {
+00154         uint32_t d32;
+00156         struct {
+00157                 unsigned sesreqscs:1;
+00158                 unsigned sesreq:1;
+00159                 unsigned reserved2_7:6;
+00160                 unsigned hstnegscs:1;
+00161                 unsigned hnpreq:1;
+00162                 unsigned hstsethnpen:1;
+00163                 unsigned devhnpen:1;
+00164                 unsigned reserved12_15:4;
+00165                 unsigned conidsts:1;
+00166                 unsigned reserved17:1;
+00167                 unsigned asesvld:1;
+00168                 unsigned bsesvld:1;
+00169                 unsigned currmod:1;
+00170                 unsigned reserved21_31:11;
+00171         } b;
+00172 } gotgctl_data_t;
+00173 
+00179 typedef union gotgint_data {
+00181         uint32_t d32;
+00183         struct {
+00185                 unsigned reserved0_1:2;
+00186 
+00188                 unsigned sesenddet:1;
+00189 
+00190                 unsigned reserved3_7:5;
+00191 
+00193                 unsigned sesreqsucstschng:1;
+00195                 unsigned hstnegsucstschng:1;
+00196 
+00197                 unsigned reserver10_16:7;
+00198 
+00200                 unsigned hstnegdet:1;
+00202                 unsigned adevtoutchng:1;
+00204                 unsigned debdone:1;
+00205 
+00206                 unsigned reserved31_20:12;
+00207 
+00208         } b;
+00209 } gotgint_data_t;
+00210 
+00216 typedef union gahbcfg_data {
+00218         uint32_t d32;
+00220         struct {
+00221                 unsigned glblintrmsk:1;
+00222 #define DWC_GAHBCFG_GLBINT_ENABLE               1
+00223 
+00224                 unsigned hburstlen:4;
+00225 #define DWC_GAHBCFG_INT_DMA_BURST_SINGLE        0
+00226 #define DWC_GAHBCFG_INT_DMA_BURST_INCR          1
+00227 #define DWC_GAHBCFG_INT_DMA_BURST_INCR4         3
+00228 #define DWC_GAHBCFG_INT_DMA_BURST_INCR8         5
+00229 #define DWC_GAHBCFG_INT_DMA_BURST_INCR16        7
+00230 
+00231                 unsigned dmaenable:1;
+00232 #define DWC_GAHBCFG_DMAENABLE                   1
+00233                 unsigned reserved:1;
+00234                 unsigned nptxfemplvl_txfemplvl:1;
+00235                 unsigned ptxfemplvl:1;
+00236 #define DWC_GAHBCFG_TXFEMPTYLVL_EMPTY           1
+00237 #define DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY       0
+00238                 unsigned reserved9_31:23;
+00239         } b;
+00240 } gahbcfg_data_t;
+00241 
+00247 typedef union gusbcfg_data {
+00249         uint32_t d32;
+00251         struct {
+00252                 unsigned toutcal:3;
+00253                 unsigned phyif:1;
+00254                 unsigned ulpi_utmi_sel:1;
+00255                 unsigned fsintf:1;
+00256                 unsigned physel:1;
+00257                 unsigned ddrsel:1;
+00258                 unsigned srpcap:1;
+00259                 unsigned hnpcap:1;
+00260                 unsigned usbtrdtim:4;
+00261                 unsigned nptxfrwnden:1;
+00262                 unsigned phylpwrclksel:1;
+00263                 unsigned otgutmifssel:1;
+00264                 unsigned ulpi_fsls:1;
+00265                 unsigned ulpi_auto_res:1;
+00266                 unsigned ulpi_clk_sus_m:1;
+00267                 unsigned ulpi_ext_vbus_drv:1;
+00268                 unsigned ulpi_int_vbus_indicator:1;
+00269                 unsigned term_sel_dl_pulse:1;
+00270                 unsigned reserved23_25:3;
+00271                 unsigned ic_usb_cap:1;
+00272                 unsigned ic_traffic_pull_remove:1;
+00273                 unsigned tx_end_delay:1;
+00274                 unsigned reserved29_31:3;
+00275         } b;
+00276 } gusbcfg_data_t;
+00277 
+00283 typedef union glpmctl_data {
+00285         uint32_t d32;
+00287         struct {
+00292                 unsigned lpm_cap_en:1;
+00297                 unsigned appl_resp:1;
+00306                 unsigned hird:4;
+00315                 unsigned rem_wkup_en:1;
+00320                 unsigned en_utmi_sleep:1;
+00323                 unsigned hird_thres:5;
+00334                 unsigned lpm_resp:2;
+00339                 unsigned prt_sleep_sts:1;
+00344                 unsigned sleep_state_resumeok:1;
+00350                 unsigned lpm_chan_index:4;
+00355                 unsigned retry_count:3;
+00361                 unsigned send_lpm:1;
+00366                 unsigned retry_count_sts:3;
+00367                 unsigned reserved28_29:2;
+00375                 unsigned hsic_connect:1;
+00379                 unsigned inv_sel_hsic:1;
+00380         } b;
+00381 } glpmcfg_data_t;
+00382 
+00388 typedef union grstctl_data {
+00390         uint32_t d32;
+00392         struct {
+00428                 unsigned csftrst:1;
+00435                 unsigned hsftrst:1;
+00444                 unsigned hstfrm:1;
+00448                 unsigned intknqflsh:1;
+00463                 unsigned rxfflsh:1;
+00478                 unsigned txfflsh:1;
+00479 
+00495                 unsigned txfnum:5;
+00497                 unsigned reserved11_29:19;
+00500                 unsigned dmareq:1;
+00503                 unsigned ahbidle:1;
+00504         } b;
+00505 } grstctl_t;
+00506 
+00512 typedef union gintmsk_data {
+00514         uint32_t d32;
+00516         struct {
+00517                 unsigned reserved0:1;
+00518                 unsigned modemismatch:1;
+00519                 unsigned otgintr:1;
+00520                 unsigned sofintr:1;
+00521                 unsigned rxstsqlvl:1;
+00522                 unsigned nptxfempty:1;
+00523                 unsigned ginnakeff:1;
+00524                 unsigned goutnakeff:1;
+00525                 unsigned reserved8:1;
+00526                 unsigned i2cintr:1;
+00527                 unsigned erlysuspend:1;
+00528                 unsigned usbsuspend:1;
+00529                 unsigned usbreset:1;
+00530                 unsigned enumdone:1;
+00531                 unsigned isooutdrop:1;
+00532                 unsigned eopframe:1;
+00533                 unsigned reserved16:1;
+00534                 unsigned epmismatch:1;
+00535                 unsigned inepintr:1;
+00536                 unsigned outepintr:1;
+00537                 unsigned incomplisoin:1;
+00538                 unsigned incomplisoout:1;
+00539                 unsigned reserved22_23:2;
+00540                 unsigned portintr:1;
+00541                 unsigned hcintr:1;
+00542                 unsigned ptxfempty:1;
+00543                 unsigned lpmtranrcvd:1;
+00544                 unsigned conidstschng:1;
+00545                 unsigned disconnect:1;
+00546                 unsigned sessreqintr:1;
+00547                 unsigned wkupintr:1;
+00548         } b;
+00549 } gintmsk_data_t;
+00555 typedef union gintsts_data {
+00557         uint32_t d32;
+00558 #define DWC_SOF_INTR_MASK 0x0008
+00559 
+00560         struct {
+00561 #define DWC_HOST_MODE 1
+00562                 unsigned curmode:1;
+00563                 unsigned modemismatch:1;
+00564                 unsigned otgintr:1;
+00565                 unsigned sofintr:1;
+00566                 unsigned rxstsqlvl:1;
+00567                 unsigned nptxfempty:1;
+00568                 unsigned ginnakeff:1;
+00569                 unsigned goutnakeff:1;
+00570                 unsigned reserved8:1;
+00571                 unsigned i2cintr:1;
+00572                 unsigned erlysuspend:1;
+00573                 unsigned usbsuspend:1;
+00574                 unsigned usbreset:1;
+00575                 unsigned enumdone:1;
+00576                 unsigned isooutdrop:1;
+00577                 unsigned eopframe:1;
+00578                 unsigned intokenrx:1;
+00579                 unsigned epmismatch:1;
+00580                 unsigned inepint:1;
+00581                 unsigned outepintr:1;
+00582                 unsigned incomplisoin:1;
+00583                 unsigned incomplisoout:1;
+00584                 unsigned reserved22_23:2;
+00585                 unsigned portintr:1;
+00586                 unsigned hcintr:1;
+00587                 unsigned ptxfempty:1;
+00588                 unsigned lpmtranrcvd:1;
+00589                 unsigned conidstschng:1;
+00590                 unsigned disconnect:1;
+00591                 unsigned sessreqintr:1;
+00592                 unsigned wkupintr:1;
+00593         } b;
+00594 } gintsts_data_t;
+00595 
+00601 typedef union device_grxsts_data {
+00603         uint32_t d32;
+00605         struct {
+00606                 unsigned epnum:4;
+00607                 unsigned bcnt:11;
+00608                 unsigned dpid:2;
+00609 
+00610 #define DWC_STS_DATA_UPDT               0x2     // OUT Data Packet
+00611 #define DWC_STS_XFER_COMP               0x3     // OUT Data Transfer Complete
+00612 
+00613 #define DWC_DSTS_GOUT_NAK               0x1     // Global OUT NAK
+00614 #define DWC_DSTS_SETUP_COMP             0x4     // Setup Phase Complete
+00615 #define DWC_DSTS_SETUP_UPDT 0x6 // SETUP Packet
+00616                 unsigned pktsts:4;
+00617                 unsigned fn:4;
+00618                 unsigned reserved:7;
+00619         } b;
+00620 } device_grxsts_data_t;
+00621 
+00627 typedef union host_grxsts_data {
+00629         uint32_t d32;
+00631         struct {
+00632                 unsigned chnum:4;
+00633                 unsigned bcnt:11;
+00634                 unsigned dpid:2;
+00635 
+00636                 unsigned pktsts:4;
+00637 #define DWC_GRXSTS_PKTSTS_IN                      0x2
+00638 #define DWC_GRXSTS_PKTSTS_IN_XFER_COMP    0x3
+00639 #define DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR 0x5
+00640 #define DWC_GRXSTS_PKTSTS_CH_HALTED               0x7
+00641 
+00642                 unsigned reserved:11;
+00643         } b;
+00644 } host_grxsts_data_t;
+00645 
+00651 typedef union fifosize_data {
+00653         uint32_t d32;
+00655         struct {
+00656                 unsigned startaddr:16;
+00657                 unsigned depth:16;
+00658         } b;
+00659 } fifosize_data_t;
+00660 
+00667 typedef union gnptxsts_data {
+00669         uint32_t d32;
+00671         struct {
+00672                 unsigned nptxfspcavail:16;
+00673                 unsigned nptxqspcavail:8;
+00684                 unsigned nptxqtop_terminate:1;
+00685                 unsigned nptxqtop_token:2;
+00686                 unsigned nptxqtop_chnep:4;
+00687                 unsigned reserved:1;
+00688         } b;
+00689 } gnptxsts_data_t;
+00690 
+00697 typedef union dtxfsts_data {
+00699         uint32_t d32;
+00701         struct {
+00702                 unsigned txfspcavail:16;
+00703                 unsigned reserved:16;
+00704         } b;
+00705 } dtxfsts_data_t;
+00706 
+00712 typedef union gi2cctl_data {
+00714         uint32_t d32;
+00716         struct {
+00717                 unsigned rwdata:8;
+00718                 unsigned regaddr:8;
+00719                 unsigned addr:7;
+00720                 unsigned i2cen:1;
+00721                 unsigned ack:1;
+00722                 unsigned i2csuspctl:1;
+00723                 unsigned i2cdevaddr:2;
+00724                 unsigned reserved:2;
+00725                 unsigned rw:1;
+00726                 unsigned bsydne:1;
+00727         } b;
+00728 } gi2cctl_data_t;
+00729 
+00735 typedef union hwcfg1_data {
+00737         uint32_t d32;
+00739         struct {
+00740                 unsigned ep_dir0:2;
+00741                 unsigned ep_dir1:2;
+00742                 unsigned ep_dir2:2;
+00743                 unsigned ep_dir3:2;
+00744                 unsigned ep_dir4:2;
+00745                 unsigned ep_dir5:2;
+00746                 unsigned ep_dir6:2;
+00747                 unsigned ep_dir7:2;
+00748                 unsigned ep_dir8:2;
+00749                 unsigned ep_dir9:2;
+00750                 unsigned ep_dir10:2;
+00751                 unsigned ep_dir11:2;
+00752                 unsigned ep_dir12:2;
+00753                 unsigned ep_dir13:2;
+00754                 unsigned ep_dir14:2;
+00755                 unsigned ep_dir15:2;
+00756         } b;
+00757 } hwcfg1_data_t;
+00758 
+00764 typedef union hwcfg2_data {
+00766         uint32_t d32;
+00768         struct {
+00769                 /* GHWCFG2 */
+00770                 unsigned op_mode:3;
+00771 #define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0
+00772 #define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1
+00773 #define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2
+00774 #define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3
+00775 #define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4
+00776 #define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5
+00777 #define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6
+00778 
+00779                 unsigned architecture:2;
+00780                 unsigned point2point:1;
+00781                 unsigned hs_phy_type:2;
+00782 #define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0
+00783 #define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1
+00784 #define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2
+00785 #define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3
+00786 
+00787                 unsigned fs_phy_type:2;
+00788                 unsigned num_dev_ep:4;
+00789                 unsigned num_host_chan:4;
+00790                 unsigned perio_ep_supported:1;
+00791                 unsigned dynamic_fifo:1;
+00792                 unsigned multi_proc_int:1;
+00793                 unsigned reserved21:1;
+00794                 unsigned nonperio_tx_q_depth:2;
+00795                 unsigned host_perio_tx_q_depth:2;
+00796                 unsigned dev_token_q_depth:5;
+00797                 unsigned reserved31:1;
+00798         } b;
+00799 } hwcfg2_data_t;
+00800 
+00806 typedef union hwcfg3_data {
+00808         uint32_t d32;
+00810         struct {
+00811                 /* GHWCFG3 */
+00812                 unsigned xfer_size_cntr_width:4;
+00813                 unsigned packet_size_cntr_width:3;
+00814                 unsigned otg_func:1;
+00815                 unsigned i2c:1;
+00816                 unsigned vendor_ctrl_if:1;
+00817                 unsigned optional_features:1;
+00818                 unsigned synch_reset_type:1;
+00819                 unsigned otg_enable_ic_usb:1;
+00820                 unsigned otg_enable_hsic:1;
+00821                 unsigned reserved14:1;
+00822                 unsigned otg_lpm_en:1;
+00823                 unsigned dfifo_depth:16;
+00824         } b;
+00825 } hwcfg3_data_t;
+00826 
+00832 typedef union hwcfg4_data {
+00834         uint32_t d32;
+00836         struct {
+00837                 unsigned num_dev_perio_in_ep:4;
+00838                 unsigned power_optimiz:1;
+00839                 unsigned min_ahb_freq:9;
+00840                 unsigned utmi_phy_data_width:2;
+00841                 unsigned num_dev_mode_ctrl_ep:4;
+00842                 unsigned iddig_filt_en:1;
+00843                 unsigned vbus_valid_filt_en:1;
+00844                 unsigned a_valid_filt_en:1;
+00845                 unsigned b_valid_filt_en:1;
+00846                 unsigned session_end_filt_en:1;
+00847                 unsigned ded_fifo_en:1;
+00848                 unsigned num_in_eps:4;
+00849                 unsigned desc_dma:1;
+00850                 unsigned desc_dma_dyn:1;
+00851         } b;
+00852 } hwcfg4_data_t;
+00853 
+00855 // Device Registers
+00865 typedef struct dwc_otg_dev_global_regs {
+00867         volatile uint32_t dcfg;
+00869         volatile uint32_t dctl;
+00871         volatile uint32_t dsts;
+00873         uint32_t unused;
+00876         volatile uint32_t diepmsk;
+00879         volatile uint32_t doepmsk;
+00881         volatile uint32_t daint;
+00884         volatile uint32_t daintmsk;
+00887         volatile uint32_t dtknqr1;
+00890         volatile uint32_t dtknqr2;
+00892         volatile uint32_t dvbusdis;
+00894         volatile uint32_t dvbuspulse;
+00898         volatile uint32_t dtknqr3_dthrctl;
+00902         volatile uint32_t dtknqr4_fifoemptymsk;
+00905         volatile uint32_t deachint;
+00908         volatile uint32_t deachintmsk;
+00911         volatile uint32_t diepeachintmsk[MAX_EPS_CHANNELS];
+00914         volatile uint32_t doepeachintmsk[MAX_EPS_CHANNELS];
+00915 } dwc_otg_device_global_regs_t;
+00916 
+00923 typedef union dcfg_data {
+00925         uint32_t d32;
+00927         struct {
+00929                 unsigned devspd:2;
+00931                 unsigned nzstsouthshk:1;
+00932 #define DWC_DCFG_SEND_STALL 1
+00933 
+00934                 unsigned reserved3:1;
+00936                 unsigned devaddr:7;
+00938                 unsigned perfrint:2;
+00939 #define DWC_DCFG_FRAME_INTERVAL_80 0
+00940 #define DWC_DCFG_FRAME_INTERVAL_85 1
+00941 #define DWC_DCFG_FRAME_INTERVAL_90 2
+00942 #define DWC_DCFG_FRAME_INTERVAL_95 3
+00943 
+00944                 unsigned reserved13_17:5;
+00946                 unsigned epmscnt:5;
+00948                 unsigned descdma:1;
+00949         } b;
+00950 } dcfg_data_t;
+00951 
+00957 typedef union dctl_data {
+00959         uint32_t d32;
+00961         struct {
+00963                 unsigned rmtwkupsig:1;
+00965                 unsigned sftdiscon:1;
+00967                 unsigned gnpinnaksts:1;
+00969                 unsigned goutnaksts:1;
+00971                 unsigned tstctl:3;
+00973                 unsigned sgnpinnak:1;
+00975                 unsigned cgnpinnak:1;
+00977                 unsigned sgoutnak:1;
+00979                 unsigned cgoutnak:1;
+00980 
+00982                 unsigned pwronprgdone:1;
+00984                 unsigned gcontbna:1;
+00986                 unsigned gmc:2;
+00988                 unsigned ifrmnum:1;
+00990                 unsigned nakonbble:1;
+00991 
+00992                 unsigned reserved17_31:15;
+00993         } b;
+00994 } dctl_data_t;
+00995 
+01001 typedef union dsts_data {
+01003         uint32_t d32;
+01005         struct {
+01007                 unsigned suspsts:1;
+01009                 unsigned enumspd:2;
+01010 #define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0
+01011 #define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1
+01012 #define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ               2
+01013 #define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ              3
+01014 
+01015                 unsigned errticerr:1;
+01016                 unsigned reserved4_7:4;
+01018                 unsigned soffn:14;
+01019                 unsigned reserved22_31:10;
+01020         } b;
+01021 } dsts_data_t;
+01022 
+01030 typedef union diepint_data {
+01032         uint32_t d32;
+01034         struct {
+01036                 unsigned xfercompl:1;
+01038                 unsigned epdisabled:1;
+01040                 unsigned ahberr:1;
+01042                 unsigned timeout:1;
+01044                 unsigned intktxfemp:1;
+01046                 unsigned intknepmis:1;
+01048                 unsigned inepnakeff:1;
+01050                 unsigned emptyintr:1;
+01051 
+01052                 unsigned txfifoundrn:1;
+01053 
+01055                 unsigned bna:1;
+01056 
+01057                 unsigned reserved10_12:3;
+01059                 unsigned nak:1;
+01060 
+01061                 unsigned reserved14_31:18;
+01062         } b;
+01063 } diepint_data_t;
+01064 
+01069 typedef union diepint_data diepmsk_data_t;
+01070 
+01078 typedef union doepint_data {
+01080         uint32_t d32;
+01082         struct {
+01084                 unsigned xfercompl:1;
+01086                 unsigned epdisabled:1;
+01088                 unsigned ahberr:1;
+01090                 unsigned setup:1;
+01092                 unsigned outtknepdis:1;
+01093 
+01094                 unsigned stsphsercvd:1;
+01096                 unsigned back2backsetup:1;
+01097 
+01098                 unsigned reserved7:1;
+01100                 unsigned outpkterr:1;
+01102                 unsigned bna:1;
+01103 
+01104                 unsigned reserved10:1;
+01106                 unsigned pktdrpsts:1;
+01108                 unsigned babble:1;
+01110                 unsigned nak:1;
+01112                 unsigned nyet:1;
+01113 
+01114                 unsigned reserved15_31:17;
+01115         } b;
+01116 } doepint_data_t;
+01117 
+01122 typedef union doepint_data doepmsk_data_t;
+01123 
+01130 typedef union daint_data {
+01132         uint32_t d32;
+01134         struct {
+01136                 unsigned in:16;
+01138                 unsigned out:16;
+01139         } ep;
+01140         struct {
+01142                 unsigned inep0:1;
+01143                 unsigned inep1:1;
+01144                 unsigned inep2:1;
+01145                 unsigned inep3:1;
+01146                 unsigned inep4:1;
+01147                 unsigned inep5:1;
+01148                 unsigned inep6:1;
+01149                 unsigned inep7:1;
+01150                 unsigned inep8:1;
+01151                 unsigned inep9:1;
+01152                 unsigned inep10:1;
+01153                 unsigned inep11:1;
+01154                 unsigned inep12:1;
+01155                 unsigned inep13:1;
+01156                 unsigned inep14:1;
+01157                 unsigned inep15:1;
+01159                 unsigned outep0:1;
+01160                 unsigned outep1:1;
+01161                 unsigned outep2:1;
+01162                 unsigned outep3:1;
+01163                 unsigned outep4:1;
+01164                 unsigned outep5:1;
+01165                 unsigned outep6:1;
+01166                 unsigned outep7:1;
+01167                 unsigned outep8:1;
+01168                 unsigned outep9:1;
+01169                 unsigned outep10:1;
+01170                 unsigned outep11:1;
+01171                 unsigned outep12:1;
+01172                 unsigned outep13:1;
+01173                 unsigned outep14:1;
+01174                 unsigned outep15:1;
+01175         } b;
+01176 } daint_data_t;
+01177 
+01184 typedef union dtknq1_data {
+01186         uint32_t d32;
+01188         struct {
+01190                 unsigned intknwptr:5;
+01192                 unsigned reserved05_06:2;
+01194                 unsigned wrap_bit:1;
+01196                 unsigned epnums0_5:24;
+01197         } b;
+01198 } dtknq1_data_t;
+01199 
+01205 typedef union dthrctl_data {
+01207         uint32_t d32;
+01209         struct {
+01211                 unsigned non_iso_thr_en:1;
+01213                 unsigned iso_thr_en:1;
+01215                 unsigned tx_thr_len:9;
+01217                 unsigned ahb_thr_ratio:2;
+01219                 unsigned reserved13_15:3;
+01221                 unsigned rx_thr_en:1;
+01223                 unsigned rx_thr_len:9;
+01225                 unsigned reserved26_31:6;
+01226         } b;
+01227 } dthrctl_data_t;
+01228 
+01239 typedef struct dwc_otg_dev_in_ep_regs {
+01242         volatile uint32_t diepctl;
+01244         uint32_t reserved04;
+01247         volatile uint32_t diepint;
+01249         uint32_t reserved0C;
+01252         volatile uint32_t dieptsiz;
+01255         volatile uint32_t diepdma;
+01258         volatile uint32_t dtxfsts;
+01261         volatile uint32_t diepdmab;
+01262 } dwc_otg_dev_in_ep_regs_t;
+01263 
+01274 typedef struct dwc_otg_dev_out_ep_regs {
+01277         volatile uint32_t doepctl;
+01280         volatile uint32_t doepfn;
+01283         volatile uint32_t doepint;
+01285         uint32_t reserved0C;
+01288         volatile uint32_t doeptsiz;
+01291         volatile uint32_t doepdma;
+01293         uint32_t unused;
+01296         uint32_t doepdmab;
+01297 } dwc_otg_dev_out_ep_regs_t;
+01298 
+01304 typedef union depctl_data {
+01306         uint32_t d32;
+01308         struct {
+01316                 unsigned mps:11;
+01317 #define DWC_DEP0CTL_MPS_64       0
+01318 #define DWC_DEP0CTL_MPS_32       1
+01319 #define DWC_DEP0CTL_MPS_16       2
+01320 #define DWC_DEP0CTL_MPS_8        3
+01321 
+01325                 unsigned nextep:4;
+01326 
+01328                 unsigned usbactep:1;
+01329 
+01344                 unsigned dpid:1;
+01345 
+01347                 unsigned naksts:1;
+01348 
+01354                 unsigned eptype:2;
+01355 
+01359                 unsigned snp:1;
+01360 
+01362                 unsigned stall:1;
+01363 
+01367                 unsigned txfnum:4;
+01368 
+01370                 unsigned cnak:1;
+01372                 unsigned snak:1;
+01381                 unsigned setd0pid:1;
+01389                 unsigned setd1pid:1;
+01390 
+01392                 unsigned epdis:1;
+01394                 unsigned epena:1;
+01395         } b;
+01396 } depctl_data_t;
+01397 
+01403 typedef union deptsiz_data {
+01405         uint32_t d32;
+01407         struct {
+01409                 unsigned xfersize:19;
+01411                 unsigned pktcnt:10;
+01413                 unsigned mc:2;
+01414                 unsigned reserved:1;
+01415         } b;
+01416 } deptsiz_data_t;
+01417 
+01423 typedef union deptsiz0_data {
+01425         uint32_t d32;
+01427         struct {
+01429                 unsigned xfersize:7;
+01431                 unsigned reserved7_18:12;
+01433                 unsigned pktcnt:1;
+01435                 unsigned reserved20_28:9;
+01437                 unsigned supcnt:2;
+01438                 unsigned reserved31;
+01439         } b;
+01440 } deptsiz0_data_t;
+01441 
+01443 // DMA Descriptor Specific Structures
+01444 //
+01445 
+01448 #define BS_HOST_READY   0x0
+01449 #define BS_DMA_BUSY             0x1
+01450 #define BS_DMA_DONE             0x2
+01451 #define BS_HOST_BUSY    0x3
+01452 
+01455 #define RTS_SUCCESS             0x0
+01456 #define RTS_BUFFLUSH    0x1
+01457 #define RTS_RESERVED    0x2
+01458 #define RTS_BUFERR              0x3
+01459 
+01466 typedef union dev_dma_desc_sts {
+01468         uint32_t d32;
+01470         struct {
+01472                 unsigned bytes:16;
+01473 
+01474                 unsigned reserved16_22:7;
+01476                 unsigned mtrf:1;
+01478                 unsigned sr:1;
+01480                 unsigned ioc:1;
+01482                 unsigned sp:1;
+01484                 unsigned l:1;
+01486                 unsigned sts:2;
+01488                 unsigned bs:2;
+01489         } b;
+01490 
+01491 #ifdef DWC_EN_ISOC
+01492 
+01493         struct {
+01495                 unsigned rxbytes:11;
+01496 
+01497                 unsigned reserved11:1;
+01499                 unsigned framenum:11;
+01501                 unsigned pid:2;
+01503                 unsigned ioc:1;
+01505                 unsigned sp:1;
+01507                 unsigned l:1;
+01509                 unsigned rxsts:2;
+01511                 unsigned bs:2;
+01512         } b_iso_out;
+01513 
+01515         struct {
+01517                 unsigned txbytes:12;
+01519                 unsigned framenum:11;
+01521                 unsigned pid:2;
+01523                 unsigned ioc:1;
+01525                 unsigned sp:1;
+01527                 unsigned l:1;
+01529                 unsigned txsts:2;
+01531                 unsigned bs:2;
+01532         } b_iso_in;
+01533 #endif                          /* DWC_EN_ISOC */
+01534 } dev_dma_desc_sts_t;
+01535 
+01542 typedef struct dwc_otg_dev_dma_desc {
+01544         dev_dma_desc_sts_t status;
+01546         uint32_t buf;
+01547 } dwc_otg_dev_dma_desc_t;
+01548 
+01554 typedef struct dwc_otg_dev_if {
+01558         dwc_otg_device_global_regs_t *dev_global_regs;
+01559 #define DWC_DEV_GLOBAL_REG_OFFSET 0x800
+01560 
+01564         dwc_otg_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS];
+01565 #define DWC_DEV_IN_EP_REG_OFFSET 0x900
+01566 #define DWC_EP_REG_OFFSET 0x20
+01567 
+01569         dwc_otg_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS];
+01570 #define DWC_DEV_OUT_EP_REG_OFFSET 0xB00
+01571 
+01572         /* Device configuration information */
+01573         uint8_t speed;                           
+01574         uint8_t num_in_eps;              
+01575         uint8_t num_out_eps;             
+01578         uint16_t perio_tx_fifo_size[MAX_PERIO_FIFOS];
+01579 
+01581         uint16_t tx_fifo_size[MAX_TX_FIFOS];
+01582 
+01584         uint16_t rx_thr_en;
+01585         uint16_t iso_tx_thr_en;
+01586         uint16_t non_iso_tx_thr_en;
+01587 
+01588         uint16_t rx_thr_length;
+01589         uint16_t tx_thr_length;
+01590 
+01597         dwc_dma_t dma_setup_desc_addr[2];
+01598         dwc_otg_dev_dma_desc_t *setup_desc_addr[2];
+01599 
+01601         dwc_otg_dev_dma_desc_t *psetup;
+01602 
+01604         uint32_t setup_desc_index;
+01605 
+01607         dwc_dma_t dma_in_desc_addr;
+01608         dwc_otg_dev_dma_desc_t *in_desc_addr;
+01609 
+01611         dwc_dma_t dma_out_desc_addr;
+01612         dwc_otg_dev_dma_desc_t *out_desc_addr;
+01613 
+01615         uint32_t spd;
+01616 
+01617 } dwc_otg_dev_if_t;
+01618 
+01620 // Host Mode Register Structures
+01621 //
+01627 typedef struct dwc_otg_host_global_regs {
+01629         volatile uint32_t hcfg;
+01631         volatile uint32_t hfir;
+01633         volatile uint32_t hfnum;
+01635         uint32_t reserved40C;
+01637         volatile uint32_t hptxsts;
+01639         volatile uint32_t haint;
+01641         volatile uint32_t haintmsk;
+01643         volatile uint32_t hflbaddr;
+01644 } dwc_otg_host_global_regs_t;
+01645 
+01646 
+01652 typedef union hcfg_data
+01653 {
+01655         uint32_t d32;
+01656 
+01658         struct 
+01659         {
+01661                 unsigned fslspclksel:2;
+01662 #define DWC_HCFG_30_60_MHZ 0
+01663 #define DWC_HCFG_48_MHZ    1
+01664 #define DWC_HCFG_6_MHZ     2
+01665 
+01667                 unsigned fslssupp:1;
+01668                 unsigned reserved3_22 : 20;
+01670                 unsigned descdma : 1;
+01672                 unsigned frlisten: 2;
+01674                 unsigned perschedena: 1;
+01676                 unsigned perschedstat: 1;
+01677         } b;
+01678 } hcfg_data_t;
+01679 
+01684 typedef union hfir_data {
+01686         uint32_t d32;
+01687 
+01689         struct {
+01690                 unsigned frint:16;
+01691                 unsigned reserved:16;
+01692         } b;
+01693 } hfir_data_t;
+01694 
+01699 typedef union hfnum_data {
+01701         uint32_t d32;
+01702 
+01704         struct {
+01705                 unsigned frnum:16;
+01706 #define DWC_HFNUM_MAX_FRNUM 0x3FFF
+01707                 unsigned frrem:16;
+01708         } b;
+01709 } hfnum_data_t;
+01710 
+01711 typedef union hptxsts_data {
+01713         uint32_t d32;
+01714 
+01716         struct {
+01717                 unsigned ptxfspcavail:16;
+01718                 unsigned ptxqspcavail:8;
+01728                 unsigned ptxqtop_terminate:1;
+01729                 unsigned ptxqtop_token:2;
+01730                 unsigned ptxqtop_chnum:4;
+01731                 unsigned ptxqtop_odd:1;
+01732         } b;
+01733 } hptxsts_data_t;
+01734 
+01741 typedef union hprt0_data {
+01743         uint32_t d32;
+01745         struct {
+01746                 unsigned prtconnsts:1;
+01747                 unsigned prtconndet:1;
+01748                 unsigned prtena:1;
+01749                 unsigned prtenchng:1;
+01750                 unsigned prtovrcurract:1;
+01751                 unsigned prtovrcurrchng:1;
+01752                 unsigned prtres:1;
+01753                 unsigned prtsusp:1;
+01754                 unsigned prtrst:1;
+01755                 unsigned reserved9:1;
+01756                 unsigned prtlnsts:2;
+01757                 unsigned prtpwr:1;
+01758                 unsigned prttstctl:4;
+01759                 unsigned prtspd:2;
+01760 #define DWC_HPRT0_PRTSPD_HIGH_SPEED 0
+01761 #define DWC_HPRT0_PRTSPD_FULL_SPEED 1
+01762 #define DWC_HPRT0_PRTSPD_LOW_SPEED      2
+01763                 unsigned reserved19_31:13;
+01764         } b;
+01765 } hprt0_data_t;
+01766 
+01771 typedef union haint_data {
+01773         uint32_t d32;
+01775         struct {
+01776                 unsigned ch0:1;
+01777                 unsigned ch1:1;
+01778                 unsigned ch2:1;
+01779                 unsigned ch3:1;
+01780                 unsigned ch4:1;
+01781                 unsigned ch5:1;
+01782                 unsigned ch6:1;
+01783                 unsigned ch7:1;
+01784                 unsigned ch8:1;
+01785                 unsigned ch9:1;
+01786                 unsigned ch10:1;
+01787                 unsigned ch11:1;
+01788                 unsigned ch12:1;
+01789                 unsigned ch13:1;
+01790                 unsigned ch14:1;
+01791                 unsigned ch15:1;
+01792                 unsigned reserved:16;
+01793         } b;
+01794 
+01795         struct {
+01796                 unsigned chint:16;
+01797                 unsigned reserved:16;
+01798         } b2;
+01799 } haint_data_t;
+01800 
+01805 typedef union haintmsk_data {
+01807         uint32_t d32;
+01809         struct {
+01810                 unsigned ch0:1;
+01811                 unsigned ch1:1;
+01812                 unsigned ch2:1;
+01813                 unsigned ch3:1;
+01814                 unsigned ch4:1;
+01815                 unsigned ch5:1;
+01816                 unsigned ch6:1;
+01817                 unsigned ch7:1;
+01818                 unsigned ch8:1;
+01819                 unsigned ch9:1;
+01820                 unsigned ch10:1;
+01821                 unsigned ch11:1;
+01822                 unsigned ch12:1;
+01823                 unsigned ch13:1;
+01824                 unsigned ch14:1;
+01825                 unsigned ch15:1;
+01826                 unsigned reserved:16;
+01827         } b;
+01828 
+01829         struct {
+01830                 unsigned chint:16;
+01831                 unsigned reserved:16;
+01832         } b2;
+01833 } haintmsk_data_t;
+01834 
+01838 typedef struct dwc_otg_hc_regs 
+01839 {
+01841         volatile uint32_t hcchar;
+01843         volatile uint32_t hcsplt;
+01845         volatile uint32_t hcint;
+01847         volatile uint32_t hcintmsk;
+01849         volatile uint32_t hctsiz;
+01851         volatile uint32_t hcdma;
+01852         volatile uint32_t reserved;
+01854         volatile uint32_t hcdmab;
+01855 } dwc_otg_hc_regs_t;
+01856 
+01863 typedef union hcchar_data {
+01865         uint32_t d32;
+01866 
+01868         struct {
+01870                 unsigned mps:11;
+01871 
+01873                 unsigned epnum:4;
+01874 
+01876                 unsigned epdir:1;
+01877 
+01878                 unsigned reserved:1;
+01879 
+01881                 unsigned lspddev:1;
+01882 
+01884                 unsigned eptype:2;
+01885 
+01887                 unsigned multicnt:2;
+01888 
+01890                 unsigned devaddr:7;
+01891 
+01896                 unsigned oddfrm:1;
+01897 
+01899                 unsigned chdis:1;
+01900 
+01902                 unsigned chen:1;
+01903         } b;
+01904 } hcchar_data_t;
+01905 
+01906 typedef union hcsplt_data {
+01908         uint32_t d32;
+01909 
+01911         struct {
+01913                 unsigned prtaddr:7;
+01914 
+01916                 unsigned hubaddr:7;
+01917 
+01919                 unsigned xactpos:2;
+01920 #define DWC_HCSPLIT_XACTPOS_MID 0
+01921 #define DWC_HCSPLIT_XACTPOS_END 1
+01922 #define DWC_HCSPLIT_XACTPOS_BEGIN 2
+01923 #define DWC_HCSPLIT_XACTPOS_ALL 3
+01924 
+01926                 unsigned compsplt:1;
+01927 
+01929                 unsigned reserved:14;
+01930 
+01932                 unsigned spltena:1;
+01933         } b;
+01934 } hcsplt_data_t;
+01935 
+01940 typedef union hcint_data
+01941 {
+01943         uint32_t d32;
+01945         struct 
+01946         {
+01948                 unsigned xfercomp:1;
+01950                 unsigned chhltd:1;
+01952                 unsigned ahberr:1;
+01954                 unsigned stall:1;
+01956                 unsigned nak:1;
+01958                 unsigned ack:1;
+01960                 unsigned nyet:1;
+01962                 unsigned xacterr:1;
+01964                 unsigned bblerr:1;
+01966                 unsigned frmovrun:1;
+01968                 unsigned datatglerr:1;
+01970                 unsigned bna : 1;
+01972                 unsigned xcs_xact : 1;
+01974                 unsigned frm_list_roll : 1;
+01976                 unsigned reserved14_31 : 18;
+01977         } b;
+01978 } hcint_data_t;
+01979 
+01986 typedef union hcintmsk_data
+01987 {
+01989         uint32_t d32;
+01990 
+01992         struct 
+01993         {
+01994                 unsigned xfercompl : 1;
+01995                 unsigned chhltd : 1;
+01996                 unsigned ahberr : 1;
+01997                 unsigned stall : 1;
+01998                 unsigned nak : 1;
+01999                 unsigned ack : 1;
+02000                 unsigned nyet : 1;
+02001                 unsigned xacterr : 1;
+02002                 unsigned bblerr : 1;
+02003                 unsigned frmovrun : 1;
+02004                 unsigned datatglerr : 1;
+02005                 unsigned bna : 1;
+02006                 unsigned xcs_xact : 1;
+02007                 unsigned frm_list_roll : 1;
+02008                 unsigned reserved14_31 : 18;
+02009         } b;
+02010 } hcintmsk_data_t;
+02011 
+02019 typedef union hctsiz_data
+02020 {
+02022         uint32_t d32;
+02023 
+02025         struct 
+02026         {
+02028                 unsigned xfersize:19;
+02029 
+02031                 unsigned pktcnt:10;
+02032 
+02040                 unsigned pid:2;
+02041 #define DWC_HCTSIZ_DATA0 0
+02042 #define DWC_HCTSIZ_DATA1 2
+02043 #define DWC_HCTSIZ_DATA2 1
+02044 #define DWC_HCTSIZ_MDATA 3
+02045 #define DWC_HCTSIZ_SETUP 3
+02046 
+02048                 unsigned dopng:1;
+02049         } b;
+02050         
+02052         struct 
+02053         {
+02055                 unsigned schinfo : 8;
+02056                 
+02062                 unsigned ntd : 8;
+02063 
+02065                 unsigned reserved16_28 : 13;
+02066 
+02074                 unsigned pid : 2;
+02075 
+02077                 unsigned dopng : 1;
+02078         } b_ddma;
+02079 } hctsiz_data_t;
+02080 
+02081 
+02086 typedef union hcdma_data
+02087 {
+02089         uint32_t d32;
+02091         struct 
+02092         {
+02093                 unsigned reserved0_2 : 3;
+02095                 unsigned ctd : 8;
+02097                 unsigned dma_addr : 21;
+02098         } b;
+02099 } hcdma_data_t;
+02100 
+02106 typedef union host_dma_desc_sts
+02107 {
+02109         uint32_t d32;
+02112         /* for non-isochronous  */
+02113         struct {
+02115                 unsigned n_bytes : 17;
+02117                 unsigned qtd_offset : 6;
+02122                 unsigned a_qtd : 1;
+02127                 unsigned sup : 1;
+02129                 unsigned ioc : 1;
+02131                 unsigned eol : 1;
+02132                 unsigned reserved27 : 1;
+02134                 unsigned sts : 2;
+02135         #define DMA_DESC_STS_PKTERR     1
+02136                 unsigned reserved30 : 1;
+02138                 unsigned a : 1;
+02139         } b;
+02140         /* for isochronous */
+02141         struct {
+02143                 unsigned n_bytes : 12;
+02144                 unsigned reserved12_24 : 13;
+02146                 unsigned ioc : 1;
+02147                 unsigned reserved26_27 : 2;
+02149                 unsigned sts : 2;
+02150                 unsigned reserved30 : 1;
+02152                 unsigned a : 1;
+02153         } b_isoc;
+02154 } host_dma_desc_sts_t;
+02155 
+02156 #define MAX_DMA_DESC_SIZE               131071
+02157 #define MAX_DMA_DESC_NUM_GENERIC        64
+02158 #define MAX_DMA_DESC_NUM_HS_ISOC        256
+02159 #define MAX_FRLIST_EN_NUM               64
+02160 
+02166 typedef struct dwc_otg_host_dma_desc
+02167 {
+02169         host_dma_desc_sts_t     status;
+02171         uint32_t        buf;
+02172 } dwc_otg_host_dma_desc_t;
+02173 
+02181 typedef struct dwc_otg_host_if {
+02183         dwc_otg_host_global_regs_t *host_global_regs;
+02184 #define DWC_OTG_HOST_GLOBAL_REG_OFFSET 0x400
+02185 
+02187         volatile uint32_t *hprt0;
+02188 #define DWC_OTG_HOST_PORT_REGS_OFFSET 0x440
+02189 
+02191         dwc_otg_hc_regs_t *hc_regs[MAX_EPS_CHANNELS];
+02192 #define DWC_OTG_HOST_CHAN_REGS_OFFSET 0x500
+02193 #define DWC_OTG_CHAN_REGS_OFFSET 0x20
+02194 
+02195         /* Host configuration information */
+02197         uint8_t num_host_channels;
+02199         uint8_t perio_eps_supported;
+02201         uint16_t perio_tx_fifo_size;
+02202 
+02203 } dwc_otg_host_if_t;
+02204 
+02210 typedef union pcgcctl_data {
+02212         uint32_t d32;
+02213 
+02215         struct {
+02217                 unsigned stoppclk:1;
+02219                 unsigned gatehclk:1;
+02221                 unsigned pwrclmp:1;
+02223                 unsigned rstpdwnmodule:1;
+02225                 unsigned physuspended:1;
+02227                 unsigned enbl_sleep_gating:1;
+02229                 unsigned phy_in_sleep:1;
+02231                 unsigned deep_sleep:1;
+02232 
+02233                 unsigned reserved31_8:24;
+02234         } b;
+02235 } pcgcctl_data_t;
+02236 
+02237 #endif
+

Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/dwc__otg__regs_8h.html b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__regs_8h.html new file mode 100644 index 000000000000..b441305330a8 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/dwc__otg__regs_8h.html @@ -0,0 +1,1468 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_regs.h File Reference + + + + + + +

dwc_otg_regs.h File Reference

This file contains the data structures for accessing the DWC_otg core registers. More... +

+#include "dwc_otg_core_if.h"
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Structures

struct  dwc_otg_core_global_regs
 DWC_otg Core registers . More...
union  gotgctl_data
 This union represents the bit fields of the Core OTG Control and Status Register (GOTGCTL). More...
union  gotgint_data
 This union represents the bit fields of the Core OTG Interrupt Register (GOTGINT). More...
union  gahbcfg_data
 This union represents the bit fields of the Core AHB Configuration Register (GAHBCFG). More...
union  gusbcfg_data
 This union represents the bit fields of the Core USB Configuration Register (GUSBCFG). More...
union  glpmctl_data
 This union represents the bit fields of the Core LPM Configuration Register (GLPMCFG). More...
union  grstctl_data
 This union represents the bit fields of the Core Reset Register (GRSTCTL). More...
union  gintmsk_data
 This union represents the bit fields of the Core Interrupt Mask Register (GINTMSK). More...
union  gintsts_data
 This union represents the bit fields of the Core Interrupt Register (GINTSTS). More...
union  device_grxsts_data
 This union represents the bit fields in the Device Receive Status Read and Pop Registers (GRXSTSR, GRXSTSP) Read the register into the d32 element then read out the bits using the bit elements. More...
union  host_grxsts_data
 This union represents the bit fields in the Host Receive Status Read and Pop Registers (GRXSTSR, GRXSTSP) Read the register into the d32 element then read out the bits using the bit elements. More...
union  fifosize_data
 This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ, GNPTXFSIZ, DPTXFSIZn, DIEPTXFn). More...
union  gnptxsts_data
 This union represents the bit fields in the Non-Periodic Transmit FIFO/Queue Status Register (GNPTXSTS). More...
union  dtxfsts_data
 This union represents the bit fields in the Transmit FIFO Status Register (DTXFSTS). More...
union  gi2cctl_data
 This union represents the bit fields in the I2C Control Register (I2CCTL). More...
union  hwcfg1_data
 This union represents the bit fields in the User HW Config1 Register. More...
union  hwcfg2_data
 This union represents the bit fields in the User HW Config2 Register. More...
union  hwcfg3_data
 This union represents the bit fields in the User HW Config3 Register. More...
union  hwcfg4_data
 This union represents the bit fields in the User HW Config4 Register. More...
struct  dwc_otg_dev_global_regs
 Device Global Registers. More...
union  dcfg_data
 This union represents the bit fields in the Device Configuration Register. More...
union  dctl_data
 This union represents the bit fields in the Device Control Register. More...
union  dsts_data
 This union represents the bit fields in the Device Status Register. More...
union  diepint_data
 This union represents the bit fields in the Device IN EP Interrupt Register and the Device IN EP Common Mask Register. More...
union  doepint_data
 This union represents the bit fields in the Device OUT EP Interrupt Registerand Device OUT EP Common Interrupt Mask Register. More...
union  daint_data
 This union represents the bit fields in the Device All EP Interrupt and Mask Registers. More...
union  dtknq1_data
 This union represents the bit fields in the Device IN Token Queue Read Registers. More...
union  dthrctl_data
 This union represents Threshold control Register
    +
  • Read and write the register into the d32 member.
+ More...
struct  dwc_otg_dev_in_ep_regs
 Device Logical IN Endpoint-Specific Registers. More...
struct  dwc_otg_dev_out_ep_regs
 Device Logical OUT Endpoint-Specific Registers. More...
union  depctl_data
 This union represents the bit fields in the Device EP Control Register. More...
union  deptsiz_data
 This union represents the bit fields in the Device EP Transfer Size Register. More...
union  deptsiz0_data
 This union represents the bit fields in the Device EP 0 Transfer Size Register. More...
union  dev_dma_desc_sts
 This union represents the bit fields in the DMA Descriptor status quadlet. More...
struct  dwc_otg_dev_dma_desc
 DMA Descriptor structure. More...
struct  dwc_otg_dev_if
 The dwc_otg_dev_if structure contains information needed to manage the DWC_otg controller acting in device mode. More...
struct  dwc_otg_host_global_regs
 The Host Global Registers structure defines the size and relative field offsets for the Host Mode Global Registers. More...
union  hcfg_data
 This union represents the bit fields in the Host Configuration Register. More...
union  hfir_data
 This union represents the bit fields in the Host Frame Remaing/Number Register. More...
union  hfnum_data
 This union represents the bit fields in the Host Frame Remaing/Number Register. More...
union  hptxsts_data
union  hprt0_data
 This union represents the bit fields in the Host Port Control and Status Register. More...
union  haint_data
 This union represents the bit fields in the Host All Interrupt Register. More...
union  haintmsk_data
 This union represents the bit fields in the Host All Interrupt Register. More...
struct  dwc_otg_hc_regs
 Host Channel Specific Registers. More...
union  hcchar_data
 This union represents the bit fields in the Host Channel Characteristics Register. More...
union  hcsplt_data
union  hcint_data
 This union represents the bit fields in the Host All Interrupt Register. More...
union  hcintmsk_data
 This union represents the bit fields in the Host Channel Interrupt Mask Register. More...
union  hctsiz_data
 This union represents the bit fields in the Host Channel Transfer Size Register. More...
union  hcdma_data
 This union represents the bit fields in the Host DMA Address Register used in Descriptor DMA mode. More...
union  host_dma_desc_sts
 This union represents the bit fields in the DMA Descriptor status quadlet for host mode. More...
struct  dwc_otg_host_dma_desc
 Host-mode DMA Descriptor structure. More...
struct  dwc_otg_host_if
 OTG Host Interface Structure. More...
union  pcgcctl_data
 This union represents the bit fields in the Power and Clock Gating Control Register. More...

Defines

+#define DWC_GLBINTRMASK   0x0001
+#define DWC_DMAENABLE   0x0020
+#define DWC_NPTXEMPTYLVL_EMPTY   0x0080
+#define DWC_NPTXEMPTYLVL_HALFEMPTY   0x0000
+#define DWC_PTXEMPTYLVL_EMPTY   0x0100
+#define DWC_PTXEMPTYLVL_HALFEMPTY   0x0000
+#define DWC_SLAVE_ONLY_ARCH   0
+#define DWC_EXT_DMA_ARCH   1
+#define DWC_INT_DMA_ARCH   2
+#define DWC_MODE_HNP_SRP_CAPABLE   0
+#define DWC_MODE_SRP_ONLY_CAPABLE   1
+#define DWC_MODE_NO_HNP_SRP_CAPABLE   2
+#define DWC_MODE_SRP_CAPABLE_DEVICE   3
+#define DWC_MODE_NO_SRP_CAPABLE_DEVICE   4
+#define DWC_MODE_SRP_CAPABLE_HOST   5
+#define DWC_MODE_NO_SRP_CAPABLE_HOST   6
+#define DWC_GAHBCFG_GLBINT_ENABLE   1
+#define DWC_GAHBCFG_INT_DMA_BURST_SINGLE   0
+#define DWC_GAHBCFG_INT_DMA_BURST_INCR   1
+#define DWC_GAHBCFG_INT_DMA_BURST_INCR4   3
+#define DWC_GAHBCFG_INT_DMA_BURST_INCR8   5
+#define DWC_GAHBCFG_INT_DMA_BURST_INCR16   7
+#define DWC_GAHBCFG_DMAENABLE   1
+#define DWC_GAHBCFG_TXFEMPTYLVL_EMPTY   1
+#define DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY   0
+#define DWC_SOF_INTR_MASK   0x0008
+#define DWC_HOST_MODE   1
+#define DWC_STS_DATA_UPDT   0x2
+#define DWC_STS_XFER_COMP   0x3
+#define DWC_DSTS_GOUT_NAK   0x1
+#define DWC_DSTS_SETUP_COMP   0x4
+#define DWC_DSTS_SETUP_UPDT   0x6
+#define DWC_GRXSTS_PKTSTS_IN   0x2
+#define DWC_GRXSTS_PKTSTS_IN_XFER_COMP   0x3
+#define DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR   0x5
+#define DWC_GRXSTS_PKTSTS_CH_HALTED   0x7
+#define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG   0
+#define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG   1
+#define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG   2
+#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE   3
+#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE   4
+#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST   5
+#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST   6
+#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED   0
+#define DWC_HWCFG2_HS_PHY_TYPE_UTMI   1
+#define DWC_HWCFG2_HS_PHY_TYPE_ULPI   2
+#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI   3
+#define DWC_DCFG_SEND_STALL   1
+#define DWC_DCFG_FRAME_INTERVAL_80   0
+#define DWC_DCFG_FRAME_INTERVAL_85   1
+#define DWC_DCFG_FRAME_INTERVAL_90   2
+#define DWC_DCFG_FRAME_INTERVAL_95   3
+#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ   0
+#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ   1
+#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ   2
+#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ   3
+#define DWC_DEP0CTL_MPS_64   0
+#define DWC_DEP0CTL_MPS_32   1
+#define DWC_DEP0CTL_MPS_16   2
+#define DWC_DEP0CTL_MPS_8   3
+#define BS_HOST_READY   0x0
 Buffer status definitions.
+#define BS_DMA_BUSY   0x1
+#define BS_DMA_DONE   0x2
+#define BS_HOST_BUSY   0x3
+#define RTS_SUCCESS   0x0
 Receive/Transmit status definitions.
+#define RTS_BUFFLUSH   0x1
+#define RTS_RESERVED   0x2
+#define RTS_BUFERR   0x3
+#define DWC_DEV_GLOBAL_REG_OFFSET   0x800
+#define DWC_DEV_IN_EP_REG_OFFSET   0x900
+#define DWC_EP_REG_OFFSET   0x20
+#define DWC_DEV_OUT_EP_REG_OFFSET   0xB00
+#define DWC_HCFG_30_60_MHZ   0
+#define DWC_HCFG_48_MHZ   1
+#define DWC_HCFG_6_MHZ   2
+#define DWC_HFNUM_MAX_FRNUM   0x3FFF
+#define DWC_HPRT0_PRTSPD_HIGH_SPEED   0
+#define DWC_HPRT0_PRTSPD_FULL_SPEED   1
+#define DWC_HPRT0_PRTSPD_LOW_SPEED   2
+#define DWC_HCSPLIT_XACTPOS_MID   0
+#define DWC_HCSPLIT_XACTPOS_END   1
+#define DWC_HCSPLIT_XACTPOS_BEGIN   2
+#define DWC_HCSPLIT_XACTPOS_ALL   3
+#define DWC_HCTSIZ_DATA0   0
+#define DWC_HCTSIZ_DATA1   2
+#define DWC_HCTSIZ_DATA2   1
+#define DWC_HCTSIZ_MDATA   3
+#define DWC_HCTSIZ_SETUP   3
+#define DMA_DESC_STS_PKTERR   1
+#define MAX_DMA_DESC_SIZE   131071
+#define MAX_DMA_DESC_NUM_GENERIC   64
+#define MAX_DMA_DESC_NUM_HS_ISOC   256
+#define MAX_FRLIST_EN_NUM   64
+#define DWC_OTG_HOST_GLOBAL_REG_OFFSET   0x400
+#define DWC_OTG_HOST_PORT_REGS_OFFSET   0x440
+#define DWC_OTG_HOST_CHAN_REGS_OFFSET   0x500
+#define DWC_OTG_CHAN_REGS_OFFSET   0x20

Typedefs

typedef dwc_otg_core_global_regs dwc_otg_core_global_regs_t
 DWC_otg Core registers .
typedef gotgctl_data gotgctl_data_t
 This union represents the bit fields of the Core OTG Control and Status Register (GOTGCTL).
typedef gotgint_data gotgint_data_t
 This union represents the bit fields of the Core OTG Interrupt Register (GOTGINT).
typedef gahbcfg_data gahbcfg_data_t
 This union represents the bit fields of the Core AHB Configuration Register (GAHBCFG).
typedef gusbcfg_data gusbcfg_data_t
 This union represents the bit fields of the Core USB Configuration Register (GUSBCFG).
typedef glpmctl_data glpmcfg_data_t
 This union represents the bit fields of the Core LPM Configuration Register (GLPMCFG).
typedef grstctl_data grstctl_t
 This union represents the bit fields of the Core Reset Register (GRSTCTL).
typedef gintmsk_data gintmsk_data_t
 This union represents the bit fields of the Core Interrupt Mask Register (GINTMSK).
typedef gintsts_data gintsts_data_t
 This union represents the bit fields of the Core Interrupt Register (GINTSTS).
+typedef device_grxsts_data device_grxsts_data_t
 This union represents the bit fields in the Device Receive Status Read and Pop Registers (GRXSTSR, GRXSTSP) Read the register into the d32 element then read out the bits using the bit elements.
+typedef host_grxsts_data host_grxsts_data_t
 This union represents the bit fields in the Host Receive Status Read and Pop Registers (GRXSTSR, GRXSTSP) Read the register into the d32 element then read out the bits using the bit elements.
typedef fifosize_data fifosize_data_t
 This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ, GNPTXFSIZ, DPTXFSIZn, DIEPTXFn).
typedef gnptxsts_data gnptxsts_data_t
 This union represents the bit fields in the Non-Periodic Transmit FIFO/Queue Status Register (GNPTXSTS).
typedef dtxfsts_data dtxfsts_data_t
 This union represents the bit fields in the Transmit FIFO Status Register (DTXFSTS).
typedef gi2cctl_data gi2cctl_data_t
 This union represents the bit fields in the I2C Control Register (I2CCTL).
typedef hwcfg1_data hwcfg1_data_t
 This union represents the bit fields in the User HW Config1 Register.
typedef hwcfg2_data hwcfg2_data_t
 This union represents the bit fields in the User HW Config2 Register.
typedef hwcfg3_data hwcfg3_data_t
 This union represents the bit fields in the User HW Config3 Register.
typedef hwcfg4_data hwcfg4_data_t
 This union represents the bit fields in the User HW Config4 Register.
typedef dwc_otg_dev_global_regs dwc_otg_device_global_regs_t
 Device Global Registers.
typedef dcfg_data dcfg_data_t
 This union represents the bit fields in the Device Configuration Register.
typedef dctl_data dctl_data_t
 This union represents the bit fields in the Device Control Register.
typedef dsts_data dsts_data_t
 This union represents the bit fields in the Device Status Register.
typedef diepint_data diepint_data_t
 This union represents the bit fields in the Device IN EP Interrupt Register and the Device IN EP Common Mask Register.
+typedef diepint_data diepmsk_data_t
 This union represents the bit fields in the Device IN EP Common/Dedicated Interrupt Mask Register.
typedef doepint_data doepint_data_t
 This union represents the bit fields in the Device OUT EP Interrupt Registerand Device OUT EP Common Interrupt Mask Register.
+typedef doepint_data doepmsk_data_t
 This union represents the bit fields in the Device OUT EP Common/Dedicated Interrupt Mask Register.
typedef daint_data daint_data_t
 This union represents the bit fields in the Device All EP Interrupt and Mask Registers.
typedef dtknq1_data dtknq1_data_t
 This union represents the bit fields in the Device IN Token Queue Read Registers.
typedef dthrctl_data dthrctl_data_t
 This union represents Threshold control Register
    +
  • Read and write the register into the d32 member.
+
typedef dwc_otg_dev_in_ep_regs dwc_otg_dev_in_ep_regs_t
 Device Logical IN Endpoint-Specific Registers.
typedef dwc_otg_dev_out_ep_regs dwc_otg_dev_out_ep_regs_t
 Device Logical OUT Endpoint-Specific Registers.
typedef depctl_data depctl_data_t
 This union represents the bit fields in the Device EP Control Register.
typedef deptsiz_data deptsiz_data_t
 This union represents the bit fields in the Device EP Transfer Size Register.
typedef deptsiz0_data deptsiz0_data_t
 This union represents the bit fields in the Device EP 0 Transfer Size Register.
typedef dev_dma_desc_sts dev_dma_desc_sts_t
 This union represents the bit fields in the DMA Descriptor status quadlet.
typedef dwc_otg_dev_dma_desc dwc_otg_dev_dma_desc_t
 DMA Descriptor structure.
typedef dwc_otg_dev_if dwc_otg_dev_if_t
 The dwc_otg_dev_if structure contains information needed to manage the DWC_otg controller acting in device mode.
typedef dwc_otg_host_global_regs dwc_otg_host_global_regs_t
 The Host Global Registers structure defines the size and relative field offsets for the Host Mode Global Registers.
typedef hcfg_data hcfg_data_t
 This union represents the bit fields in the Host Configuration Register.
+typedef hfir_data hfir_data_t
 This union represents the bit fields in the Host Frame Remaing/Number Register.
+typedef hfnum_data hfnum_data_t
 This union represents the bit fields in the Host Frame Remaing/Number Register.
+typedef hptxsts_data hptxsts_data_t
typedef hprt0_data hprt0_data_t
 This union represents the bit fields in the Host Port Control and Status Register.
+typedef haint_data haint_data_t
 This union represents the bit fields in the Host All Interrupt Register.
+typedef haintmsk_data haintmsk_data_t
 This union represents the bit fields in the Host All Interrupt Register.
typedef dwc_otg_hc_regs dwc_otg_hc_regs_t
 Host Channel Specific Registers.
typedef hcchar_data hcchar_data_t
 This union represents the bit fields in the Host Channel Characteristics Register.
+typedef hcsplt_data hcsplt_data_t
+typedef hcint_data hcint_data_t
 This union represents the bit fields in the Host All Interrupt Register.
typedef hcintmsk_data hcintmsk_data_t
 This union represents the bit fields in the Host Channel Interrupt Mask Register.
typedef hctsiz_data hctsiz_data_t
 This union represents the bit fields in the Host Channel Transfer Size Register.
+typedef hcdma_data hcdma_data_t
 This union represents the bit fields in the Host DMA Address Register used in Descriptor DMA mode.
typedef host_dma_desc_sts host_dma_desc_sts_t
 This union represents the bit fields in the DMA Descriptor status quadlet for host mode.
typedef dwc_otg_host_dma_desc dwc_otg_host_dma_desc_t
 Host-mode DMA Descriptor structure.
typedef dwc_otg_host_if dwc_otg_host_if_t
 OTG Host Interface Structure.
typedef pcgcctl_data pcgcctl_data_t
 This union represents the bit fields in the Power and Clock Gating Control Register.
+


Detailed Description

+This file contains the data structures for accessing the DWC_otg core registers. +

+The application interfaces with the HS OTG core by reading from and writing to the Control and Status Register (CSR) space through the AHB Slave interface. These registers are 32 bits wide, and the addresses are 32-bit-block aligned. CSRs are classified as follows:

    +
  • Core Global Registers
  • Device Mode Registers
  • Device Global Registers
  • Device Endpoint Specific Registers
  • Host Mode Registers
  • Host Global Registers
  • Host Port CSRs
  • Host Channel Specific Registers
+

+Only the Core Global registers can be accessed in both Device and Host modes. When the HS OTG core is operating in one mode, either Device or Host, the application must not access registers from the other mode. When the core switches from one mode to another, the registers in the new mode of operation must be reprogrammed as they would be after a power-on reset. +

+Definition in file dwc_otg_regs.h.


Typedef Documentation

+ +
+ +
+ +

+DWC_otg Core registers . +

+The dwc_otg_core_global_regs structure defines the size and relative field offsets for the Core Global registers. +

+

+ +

+
+ + + + +
typedef union gotgctl_data gotgctl_data_t
+
+
+ +

+This union represents the bit fields of the Core OTG Control and Status Register (GOTGCTL). +

+Set the bits using the bit fields then write the d32 value to the register. +

+

+ +

+
+ + + + +
typedef union gotgint_data gotgint_data_t
+
+
+ +

+This union represents the bit fields of the Core OTG Interrupt Register (GOTGINT). +

+Set/clear the bits using the bit fields then write the d32 value to the register. +

+

+ +

+
+ + + + +
typedef union gahbcfg_data gahbcfg_data_t
+
+
+ +

+This union represents the bit fields of the Core AHB Configuration Register (GAHBCFG). +

+Set/clear the bits using the bit fields then write the d32 value to the register. +

+

+ +

+
+ + + + +
typedef union gusbcfg_data gusbcfg_data_t
+
+
+ +

+This union represents the bit fields of the Core USB Configuration Register (GUSBCFG). +

+Set the bits using the bit fields then write the d32 value to the register. +

+

+ +

+
+ + + + +
typedef union glpmctl_data glpmcfg_data_t
+
+
+ +

+This union represents the bit fields of the Core LPM Configuration Register (GLPMCFG). +

+Set the bits using bit fields then write the d32 value to the register. +

+

+ +

+
+ + + + +
typedef union grstctl_data grstctl_t
+
+
+ +

+This union represents the bit fields of the Core Reset Register (GRSTCTL). +

+Set/clear the bits using the bit fields then write the d32 value to the register. +

+

+ +

+
+ + + + +
typedef union gintmsk_data gintmsk_data_t
+
+
+ +

+This union represents the bit fields of the Core Interrupt Mask Register (GINTMSK). +

+Set/clear the bits using the bit fields then write the d32 value to the register. +

+

+ +

+
+ + + + +
typedef union gintsts_data gintsts_data_t
+
+
+ +

+This union represents the bit fields of the Core Interrupt Register (GINTSTS). +

+Set/clear the bits using the bit fields then write the d32 value to the register. +

+

+ +

+
+ + + + +
typedef union fifosize_data fifosize_data_t
+
+
+ +

+This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ, GNPTXFSIZ, DPTXFSIZn, DIEPTXFn). +

+Read the register into the d32 element then read out the bits using the bit elements. +

+

+ +

+
+ + + + +
typedef union gnptxsts_data gnptxsts_data_t
+
+
+ +

+This union represents the bit fields in the Non-Periodic Transmit FIFO/Queue Status Register (GNPTXSTS). +

+Read the register into the d32 element then read out the bits using the bit elements. +

+

+ +

+
+ + + + +
typedef union dtxfsts_data dtxfsts_data_t
+
+
+ +

+This union represents the bit fields in the Transmit FIFO Status Register (DTXFSTS). +

+Read the register into the d32 element then read out the bits using the bit elements. +

+

+ +

+
+ + + + +
typedef union gi2cctl_data gi2cctl_data_t
+
+
+ +

+This union represents the bit fields in the I2C Control Register (I2CCTL). +

+Read the register into the d32 element then read out the bits using the bit elements. +

+

+ +

+
+ + + + +
typedef union hwcfg1_data hwcfg1_data_t
+
+
+ +

+This union represents the bit fields in the User HW Config1 Register. +

+Read the register into the d32 element then read out the bits using the bit elements. +

+

+ +

+
+ + + + +
typedef union hwcfg2_data hwcfg2_data_t
+
+
+ +

+This union represents the bit fields in the User HW Config2 Register. +

+Read the register into the d32 element then read out the bits using the bit elements. +

+

+ +

+
+ + + + +
typedef union hwcfg3_data hwcfg3_data_t
+
+
+ +

+This union represents the bit fields in the User HW Config3 Register. +

+Read the register into the d32 element then read out the bits using the bit elements. +

+

+ +

+
+ + + + +
typedef union hwcfg4_data hwcfg4_data_t
+
+
+ +

+This union represents the bit fields in the User HW Config4 Register. +

+Read the register into the d32 element then read out the bits using the bit elements. +

+

+ +

+ +
+ +

+Device Global Registers. +

+Offsets 800h-BFFh

+The following structures define the size and relative field offsets for the Device Mode Registers.

+These registers are visible only in Device mode and must not be accessed in Host mode, as the results are unknown. +

+

+ +

+
+ + + + +
typedef union dcfg_data dcfg_data_t
+
+
+ +

+This union represents the bit fields in the Device Configuration Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. Write the d32 member to the dcfg register. +

+

+ +

+
+ + + + +
typedef union dctl_data dctl_data_t
+
+
+ +

+This union represents the bit fields in the Device Control Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. +

+

+ +

+
+ + + + +
typedef union dsts_data dsts_data_t
+
+
+ +

+This union represents the bit fields in the Device Status Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. +

+

+ +

+
+ + + + +
typedef union diepint_data diepint_data_t
+
+
+ +

+This union represents the bit fields in the Device IN EP Interrupt Register and the Device IN EP Common Mask Register. +

+

    +
  • Read the register into the d32 member then set/clear the bits using the bit elements.
+ +
+

+ +

+
+ + + + +
typedef union doepint_data doepint_data_t
+
+
+ +

+This union represents the bit fields in the Device OUT EP Interrupt Registerand Device OUT EP Common Interrupt Mask Register. +

+

    +
  • Read the register into the d32 member then set/clear the bits using the bit elements.
+ +
+

+ +

+
+ + + + +
typedef union daint_data daint_data_t
+
+
+ +

+This union represents the bit fields in the Device All EP Interrupt and Mask Registers. +

+

    +
  • Read the register into the d32 member then set/clear the bits using the bit elements.
+ +
+

+ +

+
+ + + + +
typedef union dtknq1_data dtknq1_data_t
+
+
+ +

+This union represents the bit fields in the Device IN Token Queue Read Registers. +

+

    +
  • Read the register into the d32 member.
  • READ-ONLY Register
+ +
+

+ +

+
+ + + + +
typedef union dthrctl_data dthrctl_data_t
+
+
+ +

+This union represents Threshold control Register

    +
  • Read and write the register into the d32 member.
+ +

+

    +
  • READ-WRITABLE Register
+ +
+

+ +

+ +
+ +

+Device Logical IN Endpoint-Specific Registers. +

+Offsets 900h-AFCh

+There will be one set of endpoint registers per logical endpoint implemented.

+These registers are visible only in Device mode and must not be accessed in Host mode, as the results are unknown. +

+

+ +

+ +
+ +

+Device Logical OUT Endpoint-Specific Registers. +

+Offsets: B00h-CFCh

+There will be one set of endpoint registers per logical endpoint implemented.

+These registers are visible only in Device mode and must not be accessed in Host mode, as the results are unknown. +

+

+ +

+
+ + + + +
typedef union depctl_data depctl_data_t
+
+
+ +

+This union represents the bit fields in the Device EP Control Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. +

+

+ +

+
+ + + + +
typedef union deptsiz_data deptsiz_data_t
+
+
+ +

+This union represents the bit fields in the Device EP Transfer Size Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. +

+

+ +

+
+ + + + +
typedef union deptsiz0_data deptsiz0_data_t
+
+
+ +

+This union represents the bit fields in the Device EP 0 Transfer Size Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. +

+

+ +

+
+ + + + +
typedef union dev_dma_desc_sts dev_dma_desc_sts_t
+
+
+ +

+This union represents the bit fields in the DMA Descriptor status quadlet. +

+Read the quadlet into the d32 member then set/clear the bits using the bit, b_iso_out and b_iso_in elements. +

+

+ +

+
+ + + + +
typedef struct dwc_otg_dev_dma_desc dwc_otg_dev_dma_desc_t
+
+
+ +

+DMA Descriptor structure. +

+DMA Descriptor structure contains two quadlets: Status quadlet and Data buffer pointer. +

+

+ +

+
+ + + + +
typedef struct dwc_otg_dev_if dwc_otg_dev_if_t
+
+
+ +

+The dwc_otg_dev_if structure contains information needed to manage the DWC_otg controller acting in device mode. +

+It represents the programming view of the device-specific aspects of the controller. +

+

+ +

+ +
+ +

+The Host Global Registers structure defines the size and relative field offsets for the Host Mode Global Registers. +

+Host Global Registers offsets 400h-7FFh. +

+

+ +

+
+ + + + +
typedef union hcfg_data hcfg_data_t
+
+
+ +

+This union represents the bit fields in the Host Configuration Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. Write the d32 member to the hcfg register. +

+

+ +

+
+ + + + +
typedef union hprt0_data hprt0_data_t
+
+
+ +

+This union represents the bit fields in the Host Port Control and Status Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. Write the d32 member to the hprt0 register. +

+

+ +

+
+ + + + +
typedef struct dwc_otg_hc_regs dwc_otg_hc_regs_t
+
+
+ +

+Host Channel Specific Registers. +

+500h-5FCh +

+

+ +

+
+ + + + +
typedef union hcchar_data hcchar_data_t
+
+
+ +

+This union represents the bit fields in the Host Channel Characteristics Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. Write the d32 member to the hcchar register. +

+

+ +

+
+ + + + +
typedef union hcintmsk_data hcintmsk_data_t
+
+
+ +

+This union represents the bit fields in the Host Channel Interrupt Mask Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. Write the d32 member to the hcintmsk register. +

+

+ +

+
+ + + + +
typedef union hctsiz_data hctsiz_data_t
+
+
+ +

+This union represents the bit fields in the Host Channel Transfer Size Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. Write the d32 member to the hcchar register. +

+

+ +

+
+ + + + +
typedef union host_dma_desc_sts host_dma_desc_sts_t
+
+
+ +

+This union represents the bit fields in the DMA Descriptor status quadlet for host mode. +

+Read the quadlet into the d32 member then set/clear the bits using the bit elements. +

+

+ +

+ +
+ +

+Host-mode DMA Descriptor structure. +

+DMA Descriptor structure contains two quadlets: Status quadlet and Data buffer pointer. +

+

+ +

+
+ + + + +
typedef struct dwc_otg_host_if dwc_otg_host_if_t
+
+
+ +

+OTG Host Interface Structure. +

+The OTG Host Interface Structure structure contains information needed to manage the DWC_otg controller acting in host mode. It represents the programming view of the host-specific aspects of the controller. +

+

+ +

+
+ + + + +
typedef union pcgcctl_data pcgcctl_data_t
+
+
+ +

+This union represents the bit fields in the Power and Clock Gating Control Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. +

+

+


Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/files.html b/drivers/usb/host/dwc_otg/doc/html/files.html new file mode 100644 index 000000000000..5784f074b8ae --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/files.html @@ -0,0 +1,52 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: File Index + + + + + + +

DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver File List

Here is a list of all documented files with brief descriptions: + + + + + + + + + + + + + + + + + + + + + + + + + + +
dummy_audio.c [code]
dwc_cfi_common.h [code]This file contains the CFI specific common constants, interfaces (functions and macros) and structures for Linux
dwc_otg_attr.c [code]The diagnostic interface will provide access to the controller for bringing up the hardware and testing
dwc_otg_attr.h [code]This file contains the interface to the Linux device attributes
dwc_otg_cfi.c [code]This file contains the most of the CFI implementation for the OTG
dwc_otg_cfi.h [code]This file contains the CFI related OTG PCD specific common constants, interfaces (functions and macros) and data structures
dwc_otg_cil.c [code]The Core Interface Layer provides basic services for accessing and managing the DWC_otg hardware
dwc_otg_cil.h [code]This file contains the interface to the Core Interface Layer
dwc_otg_cil_intr.c [code]The Core Interface Layer provides basic services for accessing and managing the DWC_otg hardware
dwc_otg_core_if.h [code]This file defines DWC_OTG Core API
dwc_otg_dbg.h [code]This file defines debug levels
dwc_otg_driver.c [code]The dwc_otg_driver module provides the initialization and cleanup entry points for the DWC_otg driver
dwc_otg_driver.h [code]This file contains the interface to the Linux driver
dwc_otg_hcd.c [code]This file implements HCD Core
dwc_otg_hcd.h [code]This file contains the structures, constants, and interfaces for the Host Contoller Driver (HCD)
dwc_otg_hcd_ddma.c [code]This file contains Descriptor DMA support implementation for host mode
dwc_otg_hcd_if.h [code]This file defines DWC_OTG HCD Core API
dwc_otg_hcd_intr.c [code]This file contains the implementation of the HCD Interrupt handlers
dwc_otg_hcd_linux.c [code]This file contains the implementation of the HCD
dwc_otg_hcd_queue.c [code]This file contains the functions to manage Queue Heads and Queue Transfer Descriptors
dwc_otg_pcd.c [code]This file implements PCD Core
dwc_otg_pcd.h [code]This file contains the structures, constants, and interfaces for the Perpherial Contoller Driver (PCD)
dwc_otg_pcd_if.h [code]This file defines DWC_OTG PCD Core API
dwc_otg_pcd_intr.c [code]This file contains the implementation of the PCD Interrupt handlers
dwc_otg_pcd_linux.c [code]This file implements the Peripheral Controller Driver
dwc_otg_regs.h [code]This file contains the data structures for accessing the DWC_otg core registers
+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions.html b/drivers/usb/host/dwc_otg/doc/html/functions.html new file mode 100644 index 000000000000..bcabc5e7f1ae --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions.html @@ -0,0 +1,82 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- a -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x62.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x62.html new file mode 100644 index 000000000000..95f005631930 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x62.html @@ -0,0 +1,99 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- b -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x63.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x63.html new file mode 100644 index 000000000000..838fb7f2e579 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x63.html @@ -0,0 +1,110 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- c -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x64.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x64.html new file mode 100644 index 000000000000..7d5406535b42 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x64.html @@ -0,0 +1,158 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- d -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x65.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x65.html new file mode 100644 index 000000000000..3016a51c9d86 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x65.html @@ -0,0 +1,109 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- e -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x66.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x66.html new file mode 100644 index 000000000000..3db0e3f1e7a3 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x66.html @@ -0,0 +1,81 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- f -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x67.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x67.html new file mode 100644 index 000000000000..adaebb4ea63b --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x67.html @@ -0,0 +1,95 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- g -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x68.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x68.html new file mode 100644 index 000000000000..7e37e6b4e72a --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x68.html @@ -0,0 +1,119 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- h -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x69.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x69.html new file mode 100644 index 000000000000..f6253f18de9e --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x69.html @@ -0,0 +1,121 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- i -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x6c.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x6c.html new file mode 100644 index 000000000000..9c194367fc1c --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x6c.html @@ -0,0 +1,74 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- l -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x6d.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x6d.html new file mode 100644 index 000000000000..e57901eed4b1 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x6d.html @@ -0,0 +1,79 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- m -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x6e.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x6e.html new file mode 100644 index 000000000000..b2c51c21a314 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x6e.html @@ -0,0 +1,99 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- n -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x6f.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x6f.html new file mode 100644 index 000000000000..5fcbf44959cd --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x6f.html @@ -0,0 +1,101 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- o -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x70.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x70.html new file mode 100644 index 000000000000..935f5de3d930 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x70.html @@ -0,0 +1,144 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- p -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x71.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x71.html new file mode 100644 index 000000000000..19bd972ed2dd --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x71.html @@ -0,0 +1,71 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- q -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x72.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x72.html new file mode 100644 index 000000000000..96a63373e64c --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x72.html @@ -0,0 +1,141 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- r -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x73.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x73.html new file mode 100644 index 000000000000..6a80ff479c2a --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x73.html @@ -0,0 +1,128 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- s -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x74.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x74.html new file mode 100644 index 000000000000..47f3abe7ec4d --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x74.html @@ -0,0 +1,88 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- t -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x75.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x75.html new file mode 100644 index 000000000000..83f1439bda82 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x75.html @@ -0,0 +1,78 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- u -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x76.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x76.html new file mode 100644 index 000000000000..190da71ada6d --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x76.html @@ -0,0 +1,65 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- v -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x77.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x77.html new file mode 100644 index 000000000000..e6ef4c8c11f8 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x77.html @@ -0,0 +1,79 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- w -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_0x78.html b/drivers/usb/host/dwc_otg/doc/html/functions_0x78.html new file mode 100644 index 000000000000..ff6493684113 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_0x78.html @@ -0,0 +1,77 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + +
+ +
+
+ +
+ +

+Here is a list of all documented struct and union fields with links to the struct/union documentation for each field: +

+

- x -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_func.html b/drivers/usb/host/dwc_otg/doc/html/functions_func.html new file mode 100644 index 000000000000..3689a322990a --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_func.html @@ -0,0 +1,36 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Functions + + + + + + +
+ +
+  +

+

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars.html new file mode 100644 index 000000000000..61581963e0f4 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars.html @@ -0,0 +1,82 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- a -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x62.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x62.html new file mode 100644 index 000000000000..a81951d30054 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x62.html @@ -0,0 +1,99 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- b -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x63.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x63.html new file mode 100644 index 000000000000..670e841592b8 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x63.html @@ -0,0 +1,110 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- c -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x64.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x64.html new file mode 100644 index 000000000000..75410e1d972a --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x64.html @@ -0,0 +1,157 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- d -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x65.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x65.html new file mode 100644 index 000000000000..2d0c14362888 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x65.html @@ -0,0 +1,109 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- e -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x66.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x66.html new file mode 100644 index 000000000000..aca7433f7ef5 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x66.html @@ -0,0 +1,81 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- f -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x67.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x67.html new file mode 100644 index 000000000000..a74c80a385e8 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x67.html @@ -0,0 +1,95 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- g -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x68.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x68.html new file mode 100644 index 000000000000..b89f32639656 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x68.html @@ -0,0 +1,119 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- h -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x69.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x69.html new file mode 100644 index 000000000000..822d0d2742dd --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x69.html @@ -0,0 +1,121 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- i -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x6c.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x6c.html new file mode 100644 index 000000000000..eb4da462041a --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x6c.html @@ -0,0 +1,74 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- l -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x6d.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x6d.html new file mode 100644 index 000000000000..a97be16a88d7 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x6d.html @@ -0,0 +1,79 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- m -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x6e.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x6e.html new file mode 100644 index 000000000000..254c6c9e97d6 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x6e.html @@ -0,0 +1,99 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- n -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x6f.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x6f.html new file mode 100644 index 000000000000..42089793702c --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x6f.html @@ -0,0 +1,101 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- o -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x70.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x70.html new file mode 100644 index 000000000000..b6be1be98e7d --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x70.html @@ -0,0 +1,144 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- p -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x71.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x71.html new file mode 100644 index 000000000000..65a9066faa80 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x71.html @@ -0,0 +1,71 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- q -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x72.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x72.html new file mode 100644 index 000000000000..2f53f8f64967 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x72.html @@ -0,0 +1,141 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- r -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x73.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x73.html new file mode 100644 index 000000000000..f7a0eb963c5d --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x73.html @@ -0,0 +1,128 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- s -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x74.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x74.html new file mode 100644 index 000000000000..952cc30fd044 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x74.html @@ -0,0 +1,88 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- t -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x75.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x75.html new file mode 100644 index 000000000000..54c5ed9727c4 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x75.html @@ -0,0 +1,78 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- u -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x76.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x76.html new file mode 100644 index 000000000000..6bc749520fcc --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x76.html @@ -0,0 +1,65 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- v -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x77.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x77.html new file mode 100644 index 000000000000..973b698e6651 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x77.html @@ -0,0 +1,79 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- w -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x78.html b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x78.html new file mode 100644 index 000000000000..a2e2b548dc6c --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/functions_vars_0x78.html @@ -0,0 +1,77 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields - Variables + + + + + + +
+ +
+
+ +
+ +

+  +

+

- x -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals.html b/drivers/usb/host/dwc_otg/doc/html/globals.html new file mode 100644 index 000000000000..3074c2729010 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals.html @@ -0,0 +1,87 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- _ -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x61.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x61.html new file mode 100644 index 000000000000..f9054d6cc06a --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x61.html @@ -0,0 +1,76 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- a -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x62.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x62.html new file mode 100644 index 000000000000..b9299fc63ac7 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x62.html @@ -0,0 +1,83 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- b -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x63.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x63.html new file mode 100644 index 000000000000..edb5575bd7db --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x63.html @@ -0,0 +1,100 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- c -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x64.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x64.html new file mode 100644 index 000000000000..6c33b3da5ecd --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x64.html @@ -0,0 +1,686 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- d -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x65.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x65.html new file mode 100644 index 000000000000..b8ce265b58a2 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x65.html @@ -0,0 +1,78 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- e -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x66.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x66.html new file mode 100644 index 000000000000..51aa44b0fdf1 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x66.html @@ -0,0 +1,87 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- f -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x67.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x67.html new file mode 100644 index 000000000000..3ecaaf776555 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x67.html @@ -0,0 +1,93 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- g -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x68.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x68.html new file mode 100644 index 000000000000..0790daa0ae99 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x68.html @@ -0,0 +1,129 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- h -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x69.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x69.html new file mode 100644 index 000000000000..d9269ca0ed76 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x69.html @@ -0,0 +1,76 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- i -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x6b.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x6b.html new file mode 100644 index 000000000000..d75fa77030af --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x6b.html @@ -0,0 +1,69 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- k -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x6d.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x6d.html new file mode 100644 index 000000000000..22cffaca45c1 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x6d.html @@ -0,0 +1,84 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- m -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x6e.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x6e.html new file mode 100644 index 000000000000..c77753fed0f2 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x6e.html @@ -0,0 +1,68 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- n -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x6f.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x6f.html new file mode 100644 index 000000000000..e0d373bcc3f8 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x6f.html @@ -0,0 +1,73 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- o -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x70.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x70.html new file mode 100644 index 000000000000..7b54408a42ca --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x70.html @@ -0,0 +1,84 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- p -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x71.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x71.html new file mode 100644 index 000000000000..3a79b908b60d --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x71.html @@ -0,0 +1,70 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- q -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x72.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x72.html new file mode 100644 index 000000000000..fde6703e5202 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x72.html @@ -0,0 +1,94 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- r -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x73.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x73.html new file mode 100644 index 000000000000..33736a0a3407 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x73.html @@ -0,0 +1,85 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- s -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x74.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x74.html new file mode 100644 index 000000000000..9884208a6b9a --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x74.html @@ -0,0 +1,68 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- t -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x75.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x75.html new file mode 100644 index 000000000000..3e6fe31a76b9 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x75.html @@ -0,0 +1,80 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- u -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x76.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x76.html new file mode 100644 index 000000000000..bf2c6342a389 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x76.html @@ -0,0 +1,75 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- v -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_0x77.html b/drivers/usb/host/dwc_otg/doc/html/globals_0x77.html new file mode 100644 index 000000000000..d1af4b37a7ac --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_0x77.html @@ -0,0 +1,74 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation: +

+

- w -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_defs.html b/drivers/usb/host/dwc_otg/doc/html/globals_defs.html new file mode 100644 index 000000000000..d156f9318643 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_defs.html @@ -0,0 +1,68 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- _ -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x61.html b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x61.html new file mode 100644 index 000000000000..54995e9f1976 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x61.html @@ -0,0 +1,64 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- a -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x62.html b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x62.html new file mode 100644 index 000000000000..7b3afdcf4340 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x62.html @@ -0,0 +1,71 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- b -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x63.html b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x63.html new file mode 100644 index 000000000000..ba1c6e53fa13 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x63.html @@ -0,0 +1,74 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- c -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x64.html b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x64.html new file mode 100644 index 000000000000..874f082138e8 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x64.html @@ -0,0 +1,241 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- d -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x66.html b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x66.html new file mode 100644 index 000000000000..7c3a3e76903f --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x66.html @@ -0,0 +1,71 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- f -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x67.html b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x67.html new file mode 100644 index 000000000000..0f983adc21b7 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x67.html @@ -0,0 +1,62 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- g -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x68.html b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x68.html new file mode 100644 index 000000000000..824fbd79b396 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x68.html @@ -0,0 +1,63 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- h -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x69.html b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x69.html new file mode 100644 index 000000000000..bf04bb8059ad --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x69.html @@ -0,0 +1,62 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- i -

+
Generated on Tue May 5 02:22:50 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x6d.html b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x6d.html new file mode 100644 index 000000000000..140812f099ec --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x6d.html @@ -0,0 +1,76 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- m -

+
Generated on Tue May 5 02:22:50 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x6e.html b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x6e.html new file mode 100644 index 000000000000..0413b016eeef --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x6e.html @@ -0,0 +1,62 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- n -

+
Generated on Tue May 5 02:22:50 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x6f.html b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x6f.html new file mode 100644 index 000000000000..d938dc81ed93 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x6f.html @@ -0,0 +1,67 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- o -

+
Generated on Tue May 5 02:22:50 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x72.html b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x72.html new file mode 100644 index 000000000000..84a22460d842 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x72.html @@ -0,0 +1,66 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- r -

+
Generated on Tue May 5 02:22:50 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x73.html b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x73.html new file mode 100644 index 000000000000..402040a76f0b --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x73.html @@ -0,0 +1,63 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- s -

+
Generated on Tue May 5 02:22:50 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x75.html b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x75.html new file mode 100644 index 000000000000..6f98f7c21a97 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x75.html @@ -0,0 +1,64 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- u -

+
Generated on Tue May 5 02:22:50 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x76.html b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x76.html new file mode 100644 index 000000000000..013c59a78f99 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_defs_0x76.html @@ -0,0 +1,68 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- v -

+
Generated on Tue May 5 02:22:50 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_enum.html b/drivers/usb/host/dwc_otg/doc/html/globals_enum.html new file mode 100644 index 000000000000..6ae2433e6eec --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_enum.html @@ -0,0 +1,44 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +  +

+

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_eval.html b/drivers/usb/host/dwc_otg/doc/html/globals_eval.html new file mode 100644 index 000000000000..1778d4e69d48 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_eval.html @@ -0,0 +1,43 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +  +

+

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_func.html b/drivers/usb/host/dwc_otg/doc/html/globals_func.html new file mode 100644 index 000000000000..8e2b1ee72399 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_func.html @@ -0,0 +1,77 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- _ -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_func_0x61.html b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x61.html new file mode 100644 index 000000000000..1d512d609224 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x61.html @@ -0,0 +1,70 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- a -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_func_0x62.html b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x62.html new file mode 100644 index 000000000000..59786f6bd95e --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x62.html @@ -0,0 +1,68 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- b -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_func_0x63.html b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x63.html new file mode 100644 index 000000000000..21e3050cee1f --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x63.html @@ -0,0 +1,77 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- c -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_func_0x64.html b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x64.html new file mode 100644 index 000000000000..b9c4b1c839bd --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x64.html @@ -0,0 +1,427 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- d -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_func_0x65.html b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x65.html new file mode 100644 index 000000000000..5e5869d5d246 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x65.html @@ -0,0 +1,73 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- e -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_func_0x66.html b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x66.html new file mode 100644 index 000000000000..0dd4c50199c7 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x66.html @@ -0,0 +1,72 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- f -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_func_0x67.html b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x67.html new file mode 100644 index 000000000000..aeaef34e49d3 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x67.html @@ -0,0 +1,78 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- g -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_func_0x68.html b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x68.html new file mode 100644 index 000000000000..ddc79466a640 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x68.html @@ -0,0 +1,101 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- h -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_func_0x69.html b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x69.html new file mode 100644 index 000000000000..4b5ff4a45b56 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x69.html @@ -0,0 +1,71 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- i -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_func_0x6b.html b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x6b.html new file mode 100644 index 000000000000..854a72c4f615 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x6b.html @@ -0,0 +1,66 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- k -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_func_0x6d.html b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x6d.html new file mode 100644 index 000000000000..e45997a4161c --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x6d.html @@ -0,0 +1,66 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- m -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_func_0x70.html b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x70.html new file mode 100644 index 000000000000..d4b3d4c6d309 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x70.html @@ -0,0 +1,78 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- p -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_func_0x71.html b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x71.html new file mode 100644 index 000000000000..41e644520441 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x71.html @@ -0,0 +1,67 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- q -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_func_0x72.html b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x72.html new file mode 100644 index 000000000000..7cfd7bcf8c89 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x72.html @@ -0,0 +1,80 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- r -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_func_0x73.html b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x73.html new file mode 100644 index 000000000000..72e2957a74ba --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x73.html @@ -0,0 +1,77 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- s -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_func_0x75.html b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x75.html new file mode 100644 index 000000000000..0999b3e2f28c --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x75.html @@ -0,0 +1,73 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- u -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_func_0x76.html b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x76.html new file mode 100644 index 000000000000..91caeb0e9de2 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x76.html @@ -0,0 +1,65 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- v -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_func_0x77.html b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x77.html new file mode 100644 index 000000000000..7934bcd6ff76 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_func_0x77.html @@ -0,0 +1,70 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- w -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_type.html b/drivers/usb/host/dwc_otg/doc/html/globals_type.html new file mode 100644 index 000000000000..a9b8400ce988 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_type.html @@ -0,0 +1,175 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- c -

+

- d -

+

- e -

+

- f -

+

- g -

+

- h -

+

- i -

+

- p -

+

- r -

+

- t -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/globals_vars.html b/drivers/usb/host/dwc_otg/doc/html/globals_vars.html new file mode 100644 index 000000000000..3f862ed8a24a --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/globals_vars.html @@ -0,0 +1,120 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Data Fields + + + + + + + +
+ +
+ +

+  +

+

- b -

+

- d -

+

- f -

+

- g -

+

- h -

+

- p -

+

- r -

+

- s -

+

- u -

+

- w -

+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/index.html b/drivers/usb/host/dwc_otg/doc/html/index.html new file mode 100644 index 000000000000..97a0b4709533 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/index.html @@ -0,0 +1,8 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver + + + + + diff --git a/drivers/usb/host/dwc_otg/doc/html/linux module attributes.html b/drivers/usb/host/dwc_otg/doc/html/linux module attributes.html new file mode 100644 index 000000000000..662d114c5b0e --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/linux module attributes.html @@ -0,0 +1,130 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: + + + + + +The Linux module attributes feature is used to provide the Linux Diagnostic Interface.

+These attributes are accessed through sysfs. The diagnostic interface will provide access to the controller for bringing up the hardware and testing.

+The following table shows the attributes. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name Description Access

+

mode Returns the current mode: 0 for device mode, 1 for host mode Read

+

hnpcapable Gets or sets the "HNP-capable" bit in the Core USB Configuraton Register. Read returns the current value. Read/Write

+

srpcapable Gets or sets the "SRP-capable" bit in the Core USB Configuraton Register. Read returns the current value. Read/Write

+

hsic_connect Gets or sets the "HSIC-Connect" bit in the GLPMCFG Register. Read returns the current value. Read/Write

+

inv_sel_hsic Gets or sets the "Invert Select HSIC" bit in the GLPMFG Register. Read returns the current value. Read/Write

+

hnp Initiates the Host Negotiation Protocol. Read returns the status. Read/Write

+

srp Initiates the Session Request Protocol. Read returns the status. Read/Write

+

buspower Gets or sets the Power State of the bus (0 - Off or 1 - On) Read/Write

+

bussuspend Suspends the USB bus. Read/Write

+

busconnected Gets the connection status of the bus Read

+

gotgctl Gets or sets the Core Control Status Register. Read/Write

+

gusbcfg Gets or sets the Core USB Configuration Register Read/Write

+

grxfsiz Gets or sets the Receive FIFO Size Register Read/Write

+

gnptxfsiz Gets or sets the non-periodic Transmit Size Register Read/Write

+

gpvndctl Gets or sets the PHY Vendor Control Register Read/Write

+

ggpio Gets the value in the lower 16-bits of the General Purpose IO Register or sets the upper 16 bits. Read/Write

+

guid Gets or sets the value of the User ID Register Read/Write

+

gsnpsid Gets the value of the Synopsys ID Regester Read

+

devspeed Gets or sets the device speed setting in the DCFG register Read/Write

+

enumspeed Gets the device enumeration Speed. Read

+

hptxfsiz Gets the value of the Host Periodic Transmit FIFO Read

+

hprt0 Gets or sets the value in the Host Port Control and Status Register Read/Write

+

regoffset Sets the register offset for the next Register Access Read/Write

+

regvalue Gets or sets the value of the register at the offset in the regoffset attribute. Read/Write

+

remote_wakeup On read, shows the status of Remote Wakeup. On write, initiates a remote wakeup of the host. When bit 0 is 1 and Remote Wakeup is enabled, the Remote Wakeup signalling bit in the Device Control Register is set for 1 milli-second. Read/Write

+

regdump Dumps the contents of core registers. Read

+

spramdump Dumps the contents of core registers. Read

+

hcddump Dumps the current HCD state. Read

+

hcd_frrem Shows the average value of the Frame Remaining field in the Host Frame Number/Frame Remaining register when an SOF interrupt occurs. This can be used to determine the average interrupt latency. Also shows the average Frame Remaining value for start_transfer and the "a" and "b" sample points. The "a" and "b" sample points may be used during debugging bto determine how long it takes to execute a section of the HCD code. Read

+

rd_reg_test Displays the time required to read the GNPTXFSIZ register many times (the output shows the number of times the register is read). Read

+

wr_reg_test Displays the time required to write the GNPTXFSIZ register many times (the output shows the number of times the register is written). Read

+

lpm_response Gets or sets lpm_response mode. Applicable only in device mode. Write

+

sleep_local_dev Generetates sleep signaling. Applicable only in host mode. Write

+

sleep_status Shows sleep status of device. Read

+

+

+Example usage: To get the current mode: cat /sys/devices/lm0/mode

+To power down the USB: echo 0 > /sys/devices/lm0/buspower


Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/main.html b/drivers/usb/host/dwc_otg/doc/html/main.html new file mode 100644 index 000000000000..aa55c25ed77e --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/main.html @@ -0,0 +1,21 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Main Page + + + + + +

DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver Documentation

+

+

v2.90a


Generated on Tue May 5 02:22:48 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/module parameters.html b/drivers/usb/host/dwc_otg/doc/html/module parameters.html new file mode 100644 index 000000000000..871a210e4fd3 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/module parameters.html @@ -0,0 +1,189 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: + + + + + +The following parameters may be specified when starting the module.

+These parameters define how the DWC_otg controller should be configured. Parameter values are passed to the CIL initialization function dwc_otg_cil_init

+Example: modprobe dwc_otg speed=1 otg_cap=1

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Parameter NameMeaning

+

otg_cap Specifies the OTG capabilities. The driver will automatically detect the value for this parameter if none is specified.
    +
  • 0: HNP and SRP capable (default, if available)
  • 1: SRP Only capable
  • 2: No HNP/SRP capable
+

+

dma_enable Specifies whether to use slave or DMA mode for accessing the data FIFOs. The driver will automatically detect the value for this parameter if none is specified.
    +
  • 0: Slave
  • 1: DMA (default, if available)
+

+

dma_burst_size The DMA Burst size (applicable only for External DMA Mode).
    +
  • Values: 1, 4, 8 16, 32, 64, 128, 256 (default 32)
+

+

speed Specifies the maximum speed of operation in host and device mode. The actual speed depends on the speed of the attached device and the value of phy_type.
    +
  • 0: High Speed (default)
  • 1: Full Speed
+

+

host_support_fs_ls_low_power Specifies whether low power mode is supported when attached to a Full Speed or Low Speed device in host mode.
    +
  • 0: Don't support low power mode (default)
  • 1: Support low power mode
+

+

host_ls_low_power_phy_clk Specifies the PHY clock rate in low power mode when connected to a Low Speed device in host mode. This parameter is applicable only if HOST_SUPPORT_FS_LS_LOW_POWER is enabled.
    +
  • 0: 48 MHz (default)
  • 1: 6 MHz
+

+

enable_dynamic_fifo Specifies whether FIFOs may be resized by the driver software.
    +
  • 0: Use cC FIFO size parameters
  • 1: Allow dynamic FIFO sizing (default)
+

+

data_fifo_size Total number of 4-byte words in the data FIFO memory. This memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic Tx FIFOs.
    +
  • Values: 32 to 32768 (default 8192)
+

+Note: The total FIFO memory depth in the FPGA configuration is 8192.

+

dev_rx_fifo_size Number of 4-byte words in the Rx FIFO in device mode when dynamic FIFO sizing is enabled.
    +
  • Values: 16 to 32768 (default 1064)
+

+

dev_nperio_tx_fifo_size Number of 4-byte words in the non-periodic Tx FIFO in device mode when dynamic FIFO sizing is enabled.
    +
  • Values: 16 to 32768 (default 1024)
+

+

dev_perio_tx_fifo_size_n (n = 1 to 15) Number of 4-byte words in each of the periodic Tx FIFOs in device mode when dynamic FIFO sizing is enabled.
    +
  • Values: 4 to 768 (default 256)
+

+

host_rx_fifo_size Number of 4-byte words in the Rx FIFO in host mode when dynamic FIFO sizing is enabled.
    +
  • Values: 16 to 32768 (default 1024)
+

+

host_nperio_tx_fifo_size Number of 4-byte words in the non-periodic Tx FIFO in host mode when dynamic FIFO sizing is enabled in the core.
    +
  • Values: 16 to 32768 (default 1024)
+

+

host_perio_tx_fifo_size Number of 4-byte words in the host periodic Tx FIFO when dynamic FIFO sizing is enabled.
    +
  • Values: 16 to 32768 (default 1024)
+

+

max_transfer_size The maximum transfer size supported in bytes.
    +
  • Values: 2047 to 65,535 (default 65,535)
+

+

max_packet_count The maximum number of packets in a transfer.
    +
  • Values: 15 to 511 (default 511)
+

+

host_channels The number of host channel registers to use.
    +
  • Values: 1 to 16 (default 12)
+

+Note: The FPGA configuration supports a maximum of 12 host channels.

+

dev_endpoints The number of endpoints in addition to EP0 available for device mode operations.
    +
  • Values: 1 to 15 (default 6 IN and OUT)
+

+Note: The FPGA configuration supports a maximum of 6 IN and OUT endpoints in addition to EP0.

+

phy_type Specifies the type of PHY interface to use. By default, the driver will automatically detect the phy_type.
    +
  • 0: Full Speed
  • 1: UTMI+ (default, if available)
  • 2: ULPI
+

+

phy_utmi_width Specifies the UTMI+ Data Width. This parameter is applicable for a phy_type of UTMI+. Also, this parameter is applicable only if the OTG_HSPHY_WIDTH cC parameter was set to "8 and 16 bits", meaning that the core has been configured to work at either data path width.
    +
  • Values: 8 or 16 bits (default 16)
+

+

phy_ulpi_ddr Specifies whether the ULPI operates at double or single data rate. This parameter is only applicable if phy_type is ULPI.
    +
  • 0: single data rate ULPI interface with 8 bit wide data bus (default)
  • 1: double data rate ULPI interface with 4 bit wide data bus
+

+

i2c_enable Specifies whether to use the I2C interface for full speed PHY. This parameter is only applicable if PHY_TYPE is FS.
    +
  • 0: Disabled (default)
  • 1: Enabled
+

+

otg_en_multiple_tx_fifo Specifies whether dedicatedto tx fifos are enabled for non periodic IN EPs. The driver will automatically detect the value for this parameter if none is specified.
    +
  • 0: Disabled
  • 1: Enabled (default, if available)
+

+

dev_tx_fifo_size_n (n = 1 to 15) Number of 4-byte words in each of the Tx FIFOs in device mode when dynamic FIFO sizing is enabled.
    +
  • Values: 4 to 768 (default 256)
+

+

tx_thr_length Transmit Threshold length in 32 bit double words
    +
  • Values: 8 to 128 (default 64)
+

+

rx_thr_length Receive Threshold length in 32 bit double words
    +
  • Values: 8 to 128 (default 64)
+

+

thr_ctl Specifies whether to enable Thresholding for Device mode. Bits 0, 1, 2 of this parmater specifies if thresholding is enabled for non-Iso Tx, Iso Tx and Rx transfers accordingly. The driver will automatically detect the value for this parameter if none is specified.
    +
  • Values: 0 to 7 (default 0) Bit values indicate:
  • 0: Thresholding disabled
  • 1: Thresholding enabled
+

+

dma_desc_enable Specifies whether to enable Descriptor DMA mode. The driver will automatically detect the value for this parameter if none is specified.
    +
  • 0: Descriptor DMA disabled
  • 1: Descriptor DMA (default, if available)
+

+

mpi_enable Specifies whether to enable MPI enhancement mode. The driver will automatically detect the value for this parameter if none is specified.
    +
  • 0: MPI disabled (default)
  • 1: MPI enable
+

+

pti_enable Specifies whether to enable PTI enhancement support. The driver will automatically detect the value for this parameter if none is specified.
    +
  • 0: PTI disabled (default)
  • 1: PTI enable
+

+

lpm_enable Specifies whether to enable LPM support. The driver will automatically detect the value for this parameter if none is specified.
    +
  • 0: LPM disabled
  • 1: LPM enable (default, if available)
+

+

ahb_thr_ratio Specifies AHB Threshold ratio.
    +
  • Values: 0 to 3 (default 0)
+
+


Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/pages.html b/drivers/usb/host/dwc_otg/doc/html/pages.html new file mode 100644 index 000000000000..5442a60ef243 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/pages.html @@ -0,0 +1,27 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Page Index + + + + + +

DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver Related Pages

Here is a list of all related documentation pages: +
Generated on Tue May 5 02:22:50 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/struct__ddma__align__buffer__setup.html b/drivers/usb/host/dwc_otg/doc/html/struct__ddma__align__buffer__setup.html new file mode 100644 index 000000000000..d640bc24801b --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/struct__ddma__align__buffer__setup.html @@ -0,0 +1,46 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: _ddma_align_buffer_setup Struct Reference + + + + + + +

_ddma_align_buffer_setup Struct Reference

Descriptor DMA Alignment Buffer setup structure. +More... +

+#include <dwc_otg_cfi.h> +

+ + + + + + + +

Data Fields

+uint8_t bEndpointAddress
+uint8_t bAlign
+


Detailed Description

+Descriptor DMA Alignment Buffer setup structure. +

+ +

+Definition at line 115 of file dwc_otg_cfi.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/struct__ddma__concat__buffer__setup.html b/drivers/usb/host/dwc_otg/doc/html/struct__ddma__concat__buffer__setup.html new file mode 100644 index 000000000000..b8ec739cf78b --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/struct__ddma__concat__buffer__setup.html @@ -0,0 +1,46 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: _ddma_concat_buffer_setup Struct Reference + + + + + + +

_ddma_concat_buffer_setup Struct Reference

Descriptor DMA Concatenation Buffer setup structure. +More... +

+#include <dwc_otg_cfi.h> +

+ + + + + + + +

Data Fields

+ddma_concat_buffer_setup_hdr_t hdr
+uint16_t * wTxBytes
+


Detailed Description

+Descriptor DMA Concatenation Buffer setup structure. +

+ +

+Definition at line 105 of file dwc_otg_cfi.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/struct__ddma__concat__buffer__setup__hdr.html b/drivers/usb/host/dwc_otg/doc/html/struct__ddma__concat__buffer__setup__hdr.html new file mode 100644 index 000000000000..969f0b9ee9d2 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/struct__ddma__concat__buffer__setup__hdr.html @@ -0,0 +1,49 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: _ddma_concat_buffer_setup_hdr Struct Reference + + + + + + +

_ddma_concat_buffer_setup_hdr Struct Reference

Descriptor DMA Concatenation Buffer setup structure. +More... +

+#include <dwc_otg_cfi.h> +

+ + + + + + + + + +

Data Fields

+uint8_t bEndpointAddress
+uint8_t bDescCount
+uint16_t wSize
+


Detailed Description

+Descriptor DMA Concatenation Buffer setup structure. +

+ +

+Definition at line 93 of file dwc_otg_cfi.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/struct__ddma__sg__buffer__setup.html b/drivers/usb/host/dwc_otg/doc/html/struct__ddma__sg__buffer__setup.html new file mode 100644 index 000000000000..f650509c785a --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/struct__ddma__sg__buffer__setup.html @@ -0,0 +1,57 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: _ddma_sg_buffer_setup Struct Reference + + + + + + +

_ddma_sg_buffer_setup Struct Reference

Descriptor DMA SG Buffer setup structure (SG buffer). +More... +

+#include <dwc_otg_cfi.h> +

+ + + + + + + + + + + + + +

Data Fields

+uint8_t bOutEndpointAddress
+uint8_t bInEndpointAddress
+uint8_t bOffset
+uint8_t bCount
+uint16_t wSize
+


Detailed Description

+Descriptor DMA SG Buffer setup structure (SG buffer). +

+This structure is also used for setting up a buffer for Circular DDMA. +

+ +

+Definition at line 77 of file dwc_otg_cfi.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/struct__rx__fifo__size__setup.html b/drivers/usb/host/dwc_otg/doc/html/struct__rx__fifo__size__setup.html new file mode 100644 index 000000000000..6c8b1e69b128 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/struct__rx__fifo__size__setup.html @@ -0,0 +1,43 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: _rx_fifo_size_setup Struct Reference + + + + + + +

_rx_fifo_size_setup Struct Reference

Transmit FIFO Size setup structure. +More... +

+#include <dwc_otg_cfi.h> +

+ + + + + +

Data Fields

+uint16_t wDepth
+


Detailed Description

+Transmit FIFO Size setup structure. +

+ +

+Definition at line 130 of file dwc_otg_cfi.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/struct__tx__fifo__size__setup.html b/drivers/usb/host/dwc_otg/doc/html/struct__tx__fifo__size__setup.html new file mode 100644 index 000000000000..1a4bd244a753 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/struct__tx__fifo__size__setup.html @@ -0,0 +1,46 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: _tx_fifo_size_setup Struct Reference + + + + + + +

_tx_fifo_size_setup Struct Reference

Transmit FIFO Size setup structure. +More... +

+#include <dwc_otg_cfi.h> +

+ + + + + + + +

Data Fields

+uint8_t bEndpointAddress
+uint16_t wDepth
+


Detailed Description

+Transmit FIFO Size setup structure. +

+ +

+Definition at line 123 of file dwc_otg_cfi.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structcfi__all__features__header.html b/drivers/usb/host/dwc_otg/doc/html/structcfi__all__features__header.html new file mode 100644 index 000000000000..c1ed3606d2cd --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structcfi__all__features__header.html @@ -0,0 +1,75 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: cfi_all_features_header Struct Reference + + + + + + +

cfi_all_features_header Struct Reference

This structure is the header of the Core Features dataset returned to the Host. +More... +

+#include <dwc_cfi_common.h> +

+ + + + + + + + + + + + + + + +

Data Fields

+uint16_t wTotalLen
 The total length of the features dataset returned to the Host.
uint16_t wVersion
 CFI version number inBinary-Coded Decimal (i.e., 1.00 is 100H).
+uint16_t wCoreID
 The ID of the Core.
+uint16_t wNumFeatures
 Number of features returned by VEN_CORE_GET_FEATURES request.
+


Detailed Description

+This structure is the header of the Core Features dataset returned to the Host. +

+ +

+Definition at line 69 of file dwc_cfi_common.h.


Field Documentation

+ +
+
+ + + + +
uint16_t cfi_all_features_header::wVersion
+
+
+ +

+CFI version number inBinary-Coded Decimal (i.e., 1.00 is 100H). +

+This field identifies the version of the CFI Specification with which the device is compliant. +

+Definition at line 82 of file dwc_cfi_common.h. +

+

+


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structcfi__dma__buff.html b/drivers/usb/host/dwc_otg/doc/html/structcfi__dma__buff.html new file mode 100644 index 000000000000..866833db3b19 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structcfi__dma__buff.html @@ -0,0 +1,41 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: cfi_dma_buff Struct Reference + + + + + + +

cfi_dma_buff Struct Reference

+ + + + + + +

Data Fields

+dma_addr_t addr
+uint8_t * buf
+

Detailed Description

+ +

+ +

+Definition at line 182 of file dwc_otg_cfi.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structcfi__ep.html b/drivers/usb/host/dwc_otg/doc/html/structcfi__ep.html new file mode 100644 index 000000000000..cdf155909a0b --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structcfi__ep.html @@ -0,0 +1,69 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: cfi_ep Struct Reference + + + + + + +

cfi_ep Struct Reference

The CFI wrapper of the enabled and activated dwc_otg_pcd_ep structures. +More... +

+#include <dwc_otg_cfi.h> +

+ + + + + + + + + + + + + + + + + + + + + +

Data Fields

+dwc_list_link_t lh
+dwc_otg_pcd_epep
+dwc_otg_dma_desc * dma_desc_last
+ddma_sg_buffer_setup_tbm_sg
+ddma_sg_buffer_setup_tbm_circ
+ddma_concat_buffer_setup_tbm_concat
+ddma_align_buffer_setup_tbm_align
+uint32_t xfer_len
+uint32_t desc_count
+


Detailed Description

+The CFI wrapper of the enabled and activated dwc_otg_pcd_ep structures. +

+This structure is used to store the buffer setup data for any enabled endpoint in the PCD. +

+ +

+Definition at line 156 of file dwc_otg_cfi.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structcfi__feature__desc__header.html b/drivers/usb/host/dwc_otg/doc/html/structcfi__feature__desc__header.html new file mode 100644 index 000000000000..557f335cb07d --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structcfi__feature__desc__header.html @@ -0,0 +1,60 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: cfi_feature_desc_header Struct Reference + + + + + + +

cfi_feature_desc_header Struct Reference

This structure is a header of the Core Feature descriptor dataset returned to the Host after the VEN_CORE_GET_FEATURES request. +More... +

+#include <dwc_cfi_common.h> +

+ + + + + + + + + + + + + + + + + + +

Data Fields

+uint16_t wFeatureID
 The feature ID.
+uint16_t wLength
 Length of this feature descriptor in bytes - including the length of the feature name string.
+uint16_t wDataLength
 The data length of this feature in bytes.
+uint8_t bmAttributes
 Attributes of this features D0: Access rights 0 - Read/Write 1 - Read only.
+uint8_t bNameLen
 Length of the feature name in bytes.
+


Detailed Description

+This structure is a header of the Core Feature descriptor dataset returned to the Host after the VEN_CORE_GET_FEATURES request. +

+ +

+Definition at line 99 of file dwc_cfi_common.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structcfi__ops.html b/drivers/usb/host/dwc_otg/doc/html/structcfi__ops.html new file mode 100644 index 000000000000..734204644f81 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structcfi__ops.html @@ -0,0 +1,64 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: cfi_ops Struct Reference + + + + + + +

cfi_ops Struct Reference

This is the interface for the CFI operations. +More... +

+#include <dwc_otg_cfi.h> +

+ + + + + + + + + + + + + +

Data Fields

+int(* ep_enable )(struct cfiobject *cfi, struct dwc_otg_pcd *pcd, struct dwc_otg_pcd_ep *ep)
+void *(* ep_alloc_buf )(struct cfiobject *cfi, struct dwc_otg_pcd *pcd, struct dwc_otg_pcd_ep *ep, dma_addr_t *dma, unsigned size, gfp_t flags)
+void(* release )(struct cfiobject *cfi)
+int(* ctrl_write_complete )(struct cfiobject *cfi, struct dwc_otg_pcd *pcd)
+void(* build_descriptors )(struct cfiobject *cfi, struct dwc_otg_pcd *pcd, struct dwc_otg_pcd_ep *ep, dwc_otg_pcd_request_t *req)
+


Detailed Description

+This is the interface for the CFI operations. +

+

Parameters:
+ + + + +
ep_enable Called when any endpoint is enabled and activated.
release Called when the CFI object is released and it needs to correctly deallocate the dynamic memory
ctrl_write_complete Called when the data stage of the request is complete
+
+ +

+ +

+Definition at line 199 of file dwc_otg_cfi.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structcfi__string.html b/drivers/usb/host/dwc_otg/doc/html/structcfi__string.html new file mode 100644 index 000000000000..3b79640c5253 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structcfi__string.html @@ -0,0 +1,48 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: cfi_string Struct Reference + + + + + + +

cfi_string Struct Reference

This structure describes a NULL terminated string referenced by its id field. +More... +

+#include <dwc_cfi_common.h> +

+ + + + + + + +

Data Fields

+uint16_t id
+const uint8_t * s
+


Detailed Description

+This structure describes a NULL terminated string referenced by its id field. +

+It is very similar to usb_string structure but has the id field type set to 16-bit. +

+ +

+Definition at line 136 of file dwc_cfi_common.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structcfi__usb__ctrlrequest.html b/drivers/usb/host/dwc_otg/doc/html/structcfi__usb__ctrlrequest.html new file mode 100644 index 000000000000..467657e84711 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structcfi__usb__ctrlrequest.html @@ -0,0 +1,58 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: cfi_usb_ctrlrequest Struct Reference + + + + + + +

cfi_usb_ctrlrequest Struct Reference

struct cfi_usb_ctrlrequest - the CFI implementation of the struct usb_ctrlrequest This structure encapsulates the standard usb_ctrlrequest and adds a pointer to the data returned in the data stage of a 3-stage Control Write requests. +More... +

+#include <dwc_otg_cfi.h> +

+ + + + + + + + + + + + + + + +

Data Fields

+uint8_t bRequestType
+uint8_t bRequest
+uint16_t wValue
+uint16_t wIndex
+uint16_t wLength
+uint8_t * data
+


Detailed Description

+struct cfi_usb_ctrlrequest - the CFI implementation of the struct usb_ctrlrequest This structure encapsulates the standard usb_ctrlrequest and adds a pointer to the data returned in the data stage of a 3-stage Control Write requests. +

+ +

+Definition at line 140 of file dwc_otg_cfi.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structcfiobject.html b/drivers/usb/host/dwc_otg/doc/html/structcfiobject.html new file mode 100644 index 000000000000..7e63c2286045 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structcfiobject.html @@ -0,0 +1,62 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: cfiobject Struct Reference + + + + + + +

cfiobject Struct Reference

+ + + + + + + + + + + + + + + + + + + + +

Data Fields

+cfi_ops_t ops
+dwc_otg_pcdpcd
+usb_gadget * gadget
+cfi_dma_buff_t buf_in
+cfi_dma_buff_t buf_out
+cfi_usb_ctrlrequest ctrl_req
+dwc_list_link_t active_eps
+uint8_t need_gadget_att
+uint8_t need_status_in_complete
+

Detailed Description

+ +

+ +

+Definition at line 214 of file dwc_otg_cfi.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__ep.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__ep.html new file mode 100644 index 000000000000..893fb76fce63 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__ep.html @@ -0,0 +1,192 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_ep Struct Reference + + + + + + +

dwc_ep Struct Reference

The dwc_ep structure represents the state of a single endpoint when acting in device mode. +More... +

+#include <dwc_otg_cil.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint8_t num
 EP number used for register address lookup.
+unsigned is_in:1
 EP direction 0 = OUT.
+unsigned active:1
 EP active.
+unsigned tx_fifo_num:4
 Periodic Tx FIFO # for IN EPs For INTR EP set to 0 to use non-periodic Tx FIFO If dedicated Tx FIFOs are enabled for all IN Eps - Tx FIFO # FOR IN EPs.
+unsigned type:2
 EP type: 0 - Control, 1 - ISOC, 2 - BULK, 3 - INTR.
+unsigned data_pid_start:1
 DATA start PID for INTR and BULK EP.
+unsigned even_odd_frame:1
 Frame (even/odd) for ISOC EP.
+unsigned maxpacket:11
 Max Packet bytes.
+uint32_t maxxfer
 Max Transfer size.
Transfer state
+dwc_dma_t dma_addr
 Pointer to the beginning of the transfer buffer -- do not modify during transfer.
+dwc_dma_t dma_desc_addr
+dwc_otg_dev_dma_desc_tdesc_addr
+uint8_t * start_xfer_buff
+uint8_t * xfer_buff
 pointer to the transfer buffer
+unsigned xfer_len:19
 Number of bytes to transfer.
+unsigned xfer_count:19
 Number of bytes transferred.
+unsigned sent_zlp:1
 Sent ZLP.
+unsigned total_len:19
 Total len for control transfer.
+unsigned stall_clear_flag:1
 stall clear flag
+uint32_t desc_cnt
 Allocated DMA Desc count.
+dwc_dma_t dma_addr0
 DMA addresses of ISOC buffers.
+dwc_dma_t dma_addr1
+dwc_dma_t iso_dma_desc_addr
+dwc_otg_dev_dma_desc_tiso_desc_addr
+uint8_t * xfer_buff0
 pointer to the transfer buffers
+uint8_t * xfer_buff1
+uint32_t proc_buf_num
 number of ISOC Buffer is processing
+uint32_t buf_proc_intrvl
 Interval of ISOC Buffer processing.
+uint32_t data_per_frame
 Data size for regular frame.
+uint32_t data_pattern_frame
 Data size for pattern frame.
+uint32_t sync_frame
 Frame number of pattern data.
+uint32_t bInterval
 bInterval
+uint32_t pkt_per_frm
 ISO Packet number per frame.
+uint32_t next_frame
 Next frame num for which will be setup DMA Desc.
+uint32_t pkt_cnt
 Number of packets per buffer processing.
+iso_pkt_info_tpkt_info
 Info for all isoc packets.
+uint32_t cur_pkt
 current pkt number
+uint8_t * cur_pkt_addr
 current pkt number
+uint32_t cur_pkt_dma_addr
 current pkt number
+


Detailed Description

+The dwc_ep structure represents the state of a single endpoint when acting in device mode. +

+It contains the data items needed for an endpoint to be activated and transfer packets. +

+ +

+Definition at line 88 of file dwc_otg_cil.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__hc.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__hc.html new file mode 100644 index 000000000000..b23fc5c64785 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__hc.html @@ -0,0 +1,345 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_hc Struct Reference + + + + + + +

dwc_hc Struct Reference

Host channel descriptor. +More... +

+#include <dwc_otg_cil.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

DWC_CIRCLEQ_ENTRY (dwc_hc) hc_list_entry
 Entry in list of host channels.

Data Fields

+uint8_t hc_num
 Host channel number used for register address lookup.
+unsigned dev_addr:7
 Device to access.
+unsigned ep_num:4
 EP to access.
unsigned ep_is_in:1
 EP direction.
unsigned speed:2
 EP speed.
unsigned ep_type:2
 Endpoint type.
+unsigned max_packet:11
 Max packet size in bytes.
unsigned data_pid_start:2
 PID for initial transaction.
+unsigned multi_count:2
 Number of periodic transactions per (micro)frame.
Transfer State
+uint8_t * xfer_buff
 Pointer to the current transfer buffer position.
+dwc_dma_t align_buff
 In Buffer DMA mode this buffer will be used if xfer_buff is not DWORD aligned.
+uint32_t xfer_len
 Total number of bytes to transfer.
+uint32_t xfer_count
 Number of bytes transferred so far.
+uint16_t start_pkt_count
 Packet count at start of transfer.
uint8_t xfer_started
 Flag to indicate whether the transfer has been started.
uint8_t do_ping
 Set to 1 to indicate that a PING request should be issued on this channel.
uint8_t error_state
 Set to 1 to indicate that the error count for this transaction is non-zero.
uint8_t halt_on_queue
 Set to 1 to indicate that this channel should be halted the next time a request is queued for the channel.
uint8_t halt_pending
 Set to 1 if the host channel has been halted, but the core is not finished flushing queued requests.
+dwc_otg_halt_status_e halt_status
 Reason for halting the host channel.
+uint8_t do_split
 Enable split for the channel.
+uint8_t complete_split
 Enable complete split.
+uint8_t hub_addr
 Address of high speed hub.
+uint8_t port_addr
 Port of the low/full speed device.
+uint8_t xact_pos
 Split transaction position One of the following values:
    +
  • DWC_HCSPLIT_XACTPOS_MID
  • DWC_HCSPLIT_XACTPOS_BEGIN
  • DWC_HCSPLIT_XACTPOS_END
  • DWC_HCSPLIT_XACTPOS_ALL.
+
+uint8_t short_read
 Set when the host channel does a short read.
+uint8_t requests
 Number of requests issued for this channel since it was assigned to the current transfer (not counting PINGs).
+dwc_otg_qhqh
 Queue Head for the transfer being processed by this channel.
Descriptor DMA support
+uint16_t ntd
 Number of Transfer Descriptors.
+dwc_dma_t desc_list_addr
 Descriptor List DMA address.
+uint8_t schinfo
 Scheduling micro-frame bitmap.
+


Detailed Description

+Host channel descriptor. +

+This structure represents the state of a single host channel when acting in host mode. It contains the data items needed to transfer packets to an endpoint via a host channel. +

+ +

+Definition at line 237 of file dwc_otg_cil.h.


Field Documentation

+ +
+
+ + + + +
unsigned dwc_hc::ep_is_in
+
+
+ +

+EP direction. +

+0: OUT, 1: IN +

+Definition at line 248 of file dwc_otg_cil.h. +

+

+ +

+
+ + + + +
unsigned dwc_hc::speed
+
+
+ +

+EP speed. +

+One of the following values:

    +
  • DWC_OTG_EP_SPEED_LOW
  • DWC_OTG_EP_SPEED_FULL
  • DWC_OTG_EP_SPEED_HIGH
+ +

+Definition at line 257 of file dwc_otg_cil.h. +

+

+ +

+
+ + + + +
unsigned dwc_hc::ep_type
+
+
+ +

+Endpoint type. +

+One of the following values:

    +
  • DWC_OTG_EP_TYPE_CONTROL: 0
  • DWC_OTG_EP_TYPE_ISOC: 1
  • DWC_OTG_EP_TYPE_BULK: 2
  • DWC_OTG_EP_TYPE_INTR: 3
+ +

+Definition at line 270 of file dwc_otg_cil.h. +

+

+ +

+
+ + + + +
unsigned dwc_hc::data_pid_start
+
+
+ +

+PID for initial transaction. +

+0: DATA0,
+ 1: DATA2,
+ 2: DATA1,
+ 3: MDATA (non-Control EP), SETUP (Control EP) +

+Definition at line 283 of file dwc_otg_cil.h. +

+

+ +

+
+ + + + +
uint8_t dwc_hc::xfer_started
+
+
+ +

+Flag to indicate whether the transfer has been started. +

+Set to 1 if it has been started, 0 otherwise. +

+Definition at line 314 of file dwc_otg_cil.h. +

+

+ +

+
+ + + + +
uint8_t dwc_hc::do_ping
+
+
+ +

+Set to 1 to indicate that a PING request should be issued on this channel. +

+If 0, process normally. +

+Definition at line 320 of file dwc_otg_cil.h. +

+

+ +

+
+ + + + +
uint8_t dwc_hc::error_state
+
+
+ +

+Set to 1 to indicate that the error count for this transaction is non-zero. +

+Set to 0 if the error count is 0. +

+Definition at line 326 of file dwc_otg_cil.h. +

+

+ +

+
+ + + + +
uint8_t dwc_hc::halt_on_queue
+
+
+ +

+Set to 1 to indicate that this channel should be halted the next time a request is queued for the channel. +

+This is necessary in slave mode if no request queue space is available when an attempt is made to halt the channel. +

+Definition at line 334 of file dwc_otg_cil.h. +

+

+ +

+
+ + + + +
uint8_t dwc_hc::halt_pending
+
+
+ +

+Set to 1 if the host channel has been halted, but the core is not finished flushing queued requests. +

+Otherwise 0. +

+Definition at line 340 of file dwc_otg_cil.h. +

+

+


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__cil__callbacks.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__cil__callbacks.html new file mode 100644 index 000000000000..ac0cc0733026 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__cil__callbacks.html @@ -0,0 +1,70 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_cil_callbacks Struct Reference + + + + + + +

dwc_otg_cil_callbacks Struct Reference

DWC_otg CIL callback structure. +More... +

+#include <dwc_otg_cil.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+int(* start )(void *_p)
 Start function for role change.
+int(* stop )(void *_p)
 Stop Function for role change.
+int(* disconnect )(void *_p)
 Disconnect Function for role change.
+int(* resume_wakeup )(void *_p)
 Resume/Remote wakeup Function.
+int(* suspend )(void *_p)
 Suspend function.
+int(* session_start )(void *_p)
 Session Start (SRP).
+void * p
 Pointer passed to start() and stop().
+


Detailed Description

+DWC_otg CIL callback structure. +

+This structure allows the HCD and PCD to register functions used for starting and stopping the PCD and HCD for role change on for a DRD. +

+ +

+Definition at line 1109 of file dwc_otg_cil.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__core__global__regs.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__core__global__regs.html new file mode 100644 index 000000000000..eb4401415ff8 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__core__global__regs.html @@ -0,0 +1,557 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_core_global_regs Struct Reference + + + + + + +

dwc_otg_core_global_regs Struct Reference

DWC_otg Core registers . +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

volatile uint32_t gotgctl
 OTG Control and Status Register.
volatile uint32_t gotgint
 OTG Interrupt Register.
volatile uint32_t gahbcfg
 Core AHB Configuration Register.
volatile uint32_t gusbcfg
 Core USB Configuration Register.
volatile uint32_t grstctl
 Core Reset Register.
volatile uint32_t gintsts
 Core Interrupt Register.
volatile uint32_t gintmsk
 Core Interrupt Mask Register.
volatile uint32_t grxstsr
 Receive Status Queue Read Register (Read Only).
volatile uint32_t grxstsp
 Receive Status Queue Read & POP Register (Read Only).
volatile uint32_t grxfsiz
 Receive FIFO Size Register.
volatile uint32_t gnptxfsiz
 Non Periodic Transmit FIFO Size Register.
volatile uint32_t gnptxsts
 Non Periodic Transmit FIFO/Queue Status Register (Read Only).
volatile uint32_t gi2cctl
 I2C Access Register.
volatile uint32_t gpvndctl
 PHY Vendor Control Register.
volatile uint32_t ggpio
 General Purpose Input/Output Register.
volatile uint32_t guid
 User ID Register.
volatile uint32_t gsnpsid
 Synopsys ID Register (Read Only).
volatile uint32_t ghwcfg1
 User HW Config1 Register (Read Only).
volatile uint32_t ghwcfg2
 User HW Config2 Register (Read Only).
volatile uint32_t ghwcfg3
 User HW Config3 Register (Read Only).
volatile uint32_t ghwcfg4
 User HW Config4 Register (Read Only).
+volatile uint32_t glpmcfg
 Core LPM Configuration register.
+volatile uint32_t reserved [42]
 Reserved Offset: 058h-0FFh.
volatile uint32_t hptxfsiz
 Host Periodic Transmit FIFO Size Register.
volatile uint32_t dptxfsiz_dieptxf [15]
 Device Periodic Transmit FIFO::n Register if dedicated fifos are disabled, otherwise Device Transmit FIFO::n Register.
+


Detailed Description

+DWC_otg Core registers . +

+The dwc_otg_core_global_regs structure defines the size and relative field offsets for the Core Global registers. +

+ +

+Definition at line 71 of file dwc_otg_regs.h.


Field Documentation

+ +
+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::gotgctl
+
+
+ +

+OTG Control and Status Register. +

+Offset: 000h +

+Definition at line 73 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::gotgint
+
+
+ +

+OTG Interrupt Register. +

+Offset: 004h +

+Definition at line 75 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::gahbcfg
+
+
+ +

+Core AHB Configuration Register. +

+Offset: 008h +

+Definition at line 77 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::gusbcfg
+
+
+ +

+Core USB Configuration Register. +

+Offset: 00Ch +

+Definition at line 87 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::grstctl
+
+
+ +

+Core Reset Register. +

+Offset: 010h +

+Definition at line 89 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::gintsts
+
+
+ +

+Core Interrupt Register. +

+Offset: 014h +

+Definition at line 91 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::gintmsk
+
+
+ +

+Core Interrupt Mask Register. +

+Offset: 018h +

+Definition at line 93 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::grxstsr
+
+
+ +

+Receive Status Queue Read Register (Read Only). +

+Offset: 01Ch +

+Definition at line 95 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::grxstsp
+
+
+ +

+Receive Status Queue Read & POP Register (Read Only). +

+Offset: 020h +

+Definition at line 97 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::grxfsiz
+
+
+ +

+Receive FIFO Size Register. +

+Offset: 024h +

+Definition at line 99 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::gnptxfsiz
+
+
+ +

+Non Periodic Transmit FIFO Size Register. +

+Offset: 028h +

+Definition at line 101 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::gnptxsts
+
+
+ +

+Non Periodic Transmit FIFO/Queue Status Register (Read Only). +

+Offset: 02Ch +

+Definition at line 104 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::gi2cctl
+
+
+ +

+I2C Access Register. +

+Offset: 030h +

+Definition at line 106 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::gpvndctl
+
+
+ +

+PHY Vendor Control Register. +

+Offset: 034h +

+Definition at line 108 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::ggpio
+
+
+ +

+General Purpose Input/Output Register. +

+Offset: 038h +

+Definition at line 110 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::guid
+
+
+ +

+User ID Register. +

+Offset: 03Ch +

+Definition at line 112 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::gsnpsid
+
+
+ +

+Synopsys ID Register (Read Only). +

+Offset: 040h +

+Definition at line 114 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::ghwcfg1
+
+
+ +

+User HW Config1 Register (Read Only). +

+Offset: 044h +

+Definition at line 116 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::ghwcfg2
+
+
+ +

+User HW Config2 Register (Read Only). +

+Offset: 048h +

+Definition at line 118 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::ghwcfg3
+
+
+ +

+User HW Config3 Register (Read Only). +

+Offset: 04Ch +

+Definition at line 132 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::ghwcfg4
+
+
+ +

+User HW Config4 Register (Read Only). +

+Offset: 050h +

+Definition at line 134 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::hptxfsiz
+
+
+ +

+Host Periodic Transmit FIFO Size Register. +

+Offset: 100h +

+Definition at line 140 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_core_global_regs::dptxfsiz_dieptxf[15]
+
+
+ +

+Device Periodic Transmit FIFO::n Register if dedicated fifos are disabled, otherwise Device Transmit FIFO::n Register. +

+Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15). +

+Definition at line 144 of file dwc_otg_regs.h. +

+

+


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__core__if.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__core__if.html new file mode 100644 index 000000000000..8f48162beefc --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__core__if.html @@ -0,0 +1,190 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_core_if Struct Reference + + + + + + +

dwc_otg_core_if Struct Reference

The dwc_otg_core_if structure contains information needed to manage the DWC_otg controller acting in either host or device mode. +More... +

+#include <dwc_otg_cil.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+dwc_otg_core_params_tcore_params
 Parameters that define how the core should be configured.
+dwc_otg_core_global_regs_tcore_global_regs
 Core Global registers starting at offset 000h.
+dwc_otg_dev_if_tdev_if
 Device-specific information.
+dwc_otg_host_if_thost_if
 Host-specific information.
+uint32_t snpsid
 Value from SNPSID register.
+uint8_t phy_init_done
+uint8_t srp_success
+uint8_t srp_timer_started
+volatile uint32_t * pcgcctl
 Power and Clock Gating Control Register.
+uint32_t * data_fifo [MAX_EPS_CHANNELS]
 Push/pop addresses for endpoints or host channels.
+uint16_t total_fifo_size
 Total RAM for FIFOs (Bytes).
+uint16_t rx_fifo_size
 Size of Rx FIFO (Bytes).
+uint16_t nperio_tx_fifo_size
 Size of Non-periodic Tx FIFO (Bytes).
+uint8_t dma_enable
 1 if DMA is enabled, 0 otherwise.
+uint8_t dma_desc_enable
 1 if DMA descriptor is enabled, 0 otherwise.
+uint8_t pti_enh_enable
 1 if PTI Enhancement mode is enabled, 0 otherwise.
+uint8_t multiproc_int_enable
 1 if MPI Enhancement mode is enabled, 0 otherwise.
+uint8_t en_multiple_tx_fifo
 1 if dedicated Tx FIFOs are enabled, 0 otherwise.
+uint8_t queuing_high_bandwidth
 Set to 1 if multiple packets of a high-bandwidth transfer is in process of being queued.
+hwcfg1_data_t hwcfg1
 Hardware Configuration -- stored here for convenience.
+hwcfg2_data_t hwcfg2
+hwcfg3_data_t hwcfg3
+hwcfg4_data_t hwcfg4
+hcfg_data_t hcfg
 Host and Device Configuration -- stored here for convenience.
+dcfg_data_t dcfg
+uint8_t op_state
 The operational State, during transations (a_host>>a_peripherial and b_device=>b_host) this may not match the core but allows the software to determine transitions.
uint8_t restart_hcd_on_session_req
 Set to 1 if the HCD needs to be restarted on a session request interrupt.
+dwc_otg_cil_callbackshcd_cb
 HCD callbacks.
+dwc_otg_cil_callbackspcd_cb
 PCD callbacks.
+uint32_t p_tx_msk
 Device mode Periodic Tx FIFO Mask.
+uint32_t tx_msk
 Device mode Periodic Tx FIFO Mask.
+dwc_workq_t * wq_otg
 Workqueue object used for handling several interrupts.
+dwc_timer_t * wkp_timer
 Timer object used for handling "Wakeup Detected" Interrupt.
+dwc_otg_lx_state_e lx_state
 Lx state of device.
+


Detailed Description

+The dwc_otg_core_if structure contains information needed to manage the DWC_otg controller acting in either host or device mode. +

+It represents the programming view of the controller as a whole. +

+ +

+Definition at line 680 of file dwc_otg_cil.h.


Field Documentation

+ +
+ +
+ +

+Set to 1 if the HCD needs to be restarted on a session request interrupt. +

+This is required if no connector ID status change has occurred since the HCD was last disconnected. +

+Definition at line 765 of file dwc_otg_cil.h. +

+

+


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__core__params.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__core__params.html new file mode 100644 index 000000000000..1782671ddf3d --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__core__params.html @@ -0,0 +1,606 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_core_params Struct Reference + + + + + + +

dwc_otg_core_params Struct Reference

The following parameters may be specified when starting the module. +More... +

+#include <dwc_otg_cil.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+int32_t opt
int32_t otg_cap
 Specifies the OTG capabilities.
int32_t dma_enable
 Specifies whether to use slave or DMA mode for accessing the data FIFOs.
int32_t dma_desc_enable
 When DMA mode is enabled specifies whether to use address DMA or DMA Descritor mode for accessing the data FIFOs in device mode.
int32_t dma_burst_size
 The DMA Burst size (applicable only for External DMA Mode).
int32_t speed
 Specifies the maximum speed of operation in host and device mode.
int32_t host_support_fs_ls_low_power
 Specifies whether low power mode is supported when attached to a Full Speed or Low Speed device in host mode.
int32_t host_ls_low_power_phy_clk
 Specifies the PHY clock rate in low power mode when connected to a Low Speed device in host mode.
+int32_t enable_dynamic_fifo
 0 - Use cC FIFO size parameters 1 - Allow dynamic FIFO sizing (default)
int32_t data_fifo_size
 Total number of 4-byte words in the data FIFO memory.
int32_t dev_rx_fifo_size
 Number of 4-byte words in the Rx FIFO in device mode when dynamic FIFO sizing is enabled.
int32_t dev_nperio_tx_fifo_size
 Number of 4-byte words in the non-periodic Tx FIFO in device mode when dynamic FIFO sizing is enabled.
uint32_t dev_perio_tx_fifo_size [MAX_PERIO_FIFOS]
 Number of 4-byte words in each of the periodic Tx FIFOs in device mode when dynamic FIFO sizing is enabled.
int32_t host_rx_fifo_size
 Number of 4-byte words in the Rx FIFO in host mode when dynamic FIFO sizing is enabled.
int32_t host_nperio_tx_fifo_size
 Number of 4-byte words in the non-periodic Tx FIFO in host mode when Dynamic FIFO sizing is enabled in the core.
int32_t host_perio_tx_fifo_size
 Number of 4-byte words in the host periodic Tx FIFO when dynamic FIFO sizing is enabled.
int32_t max_transfer_size
 The maximum transfer size supported in bytes.
int32_t max_packet_count
 The maximum number of packets in a transfer.
int32_t host_channels
 The number of host channel registers to use.
int32_t dev_endpoints
 The number of endpoints in addition to EP0 available for device mode operations.
int32_t phy_type
 Specifies the type of PHY interface to use.
int32_t phy_utmi_width
 Specifies the UTMI+ Data Width.
int32_t phy_ulpi_ddr
 Specifies whether the ULPI operates at double or single data rate.
+int32_t phy_ulpi_ext_vbus
 Specifies whether to use the internal or external supply to drive the vbus with a ULPI phy.
int32_t i2c_enable
 Specifies whether to use the I2Cinterface for full speed PHY.
+int32_t ulpi_fs_ls
+int32_t ts_dline
+int32_t en_multiple_tx_fifo
 Specifies whether dedicated transmit FIFOs are enabled for non periodic IN endpoints in device mode 0 - No 1 - Yes.
uint32_t dev_tx_fifo_size [MAX_TX_FIFOS]
 Number of 4-byte words in each of the Tx FIFOs in device mode when dynamic FIFO sizing is enabled.
+uint32_t thr_ctl
 Thresholding enable flag- bit 0 - enable non-ISO Tx thresholding bit 1 - enable ISO Tx thresholding bit 2 - enable Rx thresholding.
+uint32_t tx_thr_length
 Thresholding length for Tx FIFOs in 32 bit DWORDs.
+uint32_t rx_thr_length
 Thresholding length for Rx FIFOs in 32 bit DWORDs.
+int32_t lpm_enable
 Specifies whether LPM (Link Power Management) support is enabled.
+int32_t pti_enable
 Per Transfer Interrupt mode enable flag 1 - Enabled 0 - Disabled.
+int32_t mpi_enable
 Multi Processor Interrupt mode enable flag 1 - Enabled 0 - Disabled.
+int32_t ic_usb_cap
 IS_USB Capability 1 - Enabled 0 - Disabled.
+int32_t ahb_thr_ratio
 AHB Threshold Ratio 2'b00 AHB Threshold = MAC Threshold 2'b01 AHB Threshold = 1/2 MAC Threshold 2'b10 AHB Threshold = 1/4 MAC Threshold 2'b11 AHB Threshold = 1/8 MAC Threshold.
+


Detailed Description

+The following parameters may be specified when starting the module. +

+These parameters define how the DWC_otg controller should be configured. +

+ +

+Definition at line 401 of file dwc_otg_cil.h.


Field Documentation

+ +
+
+ + + + +
int32_t dwc_otg_core_params::otg_cap
+
+
+ +

+Specifies the OTG capabilities. +

+The driver will automatically detect the value for this parameter if none is specified. 0 - HNP and SRP capable (default) 1 - SRP Only capable 2 - No HNP/SRP capable +

+Definition at line 411 of file dwc_otg_cil.h. +

+

+ +

+
+ + + + +
int32_t dwc_otg_core_params::dma_enable
+
+
+ +

+Specifies whether to use slave or DMA mode for accessing the data FIFOs. +

+The driver will automatically detect the value for this parameter if none is specified. 0 - Slave 1 - DMA (default, if available) +

+Definition at line 420 of file dwc_otg_cil.h. +

+

+ +

+ +
+ +

+When DMA mode is enabled specifies whether to use address DMA or DMA Descritor mode for accessing the data FIFOs in device mode. +

+The driver will automatically detect the value for this parameter if none is specified. 0 - address DMA 1 - DMA Descriptor(default, if available) +

+Definition at line 429 of file dwc_otg_cil.h. +

+

+ +

+ +
+ +

+The DMA Burst size (applicable only for External DMA Mode). +

+1, 4, 8 16, 32, 64, 128, 256 (default 32) +

+Definition at line 433 of file dwc_otg_cil.h. +

+

+ +

+
+ + + + +
int32_t dwc_otg_core_params::speed
+
+
+ +

+Specifies the maximum speed of operation in host and device mode. +

+The actual speed depends on the speed of the attached device and the value of phy_type. The actual speed depends on the speed of the attached device. 0 - High Speed (default) 1 - Full Speed +

+Definition at line 443 of file dwc_otg_cil.h. +

+

+ +

+ +
+ +

+Specifies whether low power mode is supported when attached to a Full Speed or Low Speed device in host mode. +

+0 - Don't support low power mode (default) 1 - Support low power mode +

+Definition at line 449 of file dwc_otg_cil.h. +

+

+ +

+ +
+ +

+Specifies the PHY clock rate in low power mode when connected to a Low Speed device in host mode. +

+This parameter is applicable only if HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS then defaults to 6 MHZ otherwise 48 MHZ.

+0 - 48 MHz 1 - 6 MHz +

+Definition at line 459 of file dwc_otg_cil.h. +

+

+ +

+ +
+ +

+Total number of 4-byte words in the data FIFO memory. +

+This memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic Tx FIFOs. 32 to 32768 (default 8192) Note: The total FIFO memory depth in the FPGA configuration is 8192. +

+Definition at line 473 of file dwc_otg_cil.h. +

+

+ +

+ +
+ +

+Number of 4-byte words in the Rx FIFO in device mode when dynamic FIFO sizing is enabled. +

+16 to 32768 (default 1064) +

+Definition at line 479 of file dwc_otg_cil.h. +

+

+ +

+ +
+ +

+Number of 4-byte words in the non-periodic Tx FIFO in device mode when dynamic FIFO sizing is enabled. +

+16 to 32768 (default 1024) +

+Definition at line 485 of file dwc_otg_cil.h. +

+

+ +

+
+ + + + +
uint32_t dwc_otg_core_params::dev_perio_tx_fifo_size[MAX_PERIO_FIFOS]
+
+
+ +

+Number of 4-byte words in each of the periodic Tx FIFOs in device mode when dynamic FIFO sizing is enabled. +

+4 to 768 (default 256) +

+Definition at line 491 of file dwc_otg_cil.h. +

+

+ +

+ +
+ +

+Number of 4-byte words in the Rx FIFO in host mode when dynamic FIFO sizing is enabled. +

+16 to 32768 (default 1024) +

+Definition at line 497 of file dwc_otg_cil.h. +

+

+ +

+ +
+ +

+Number of 4-byte words in the non-periodic Tx FIFO in host mode when Dynamic FIFO sizing is enabled in the core. +

+16 to 32768 (default 1024) +

+Definition at line 503 of file dwc_otg_cil.h. +

+

+ +

+ +
+ +

+Number of 4-byte words in the host periodic Tx FIFO when dynamic FIFO sizing is enabled. +

+16 to 32768 (default 1024) +

+Definition at line 509 of file dwc_otg_cil.h. +

+

+ +

+ +
+ +

+The maximum transfer size supported in bytes. +

+2047 to 65,535 (default 65,535) +

+Definition at line 514 of file dwc_otg_cil.h. +

+

+ +

+ +
+ +

+The maximum number of packets in a transfer. +

+15 to 511 (default 511) +

+Definition at line 519 of file dwc_otg_cil.h. +

+

+ +

+ +
+ +

+The number of host channel registers to use. +

+1 to 16 (default 12) Note: The FPGA configuration supports a maximum of 12 host channels. +

+Definition at line 525 of file dwc_otg_cil.h. +

+

+ +

+ +
+ +

+The number of endpoints in addition to EP0 available for device mode operations. +

+1 to 15 (default 6 IN and OUT) Note: The FPGA configuration supports a maximum of 6 IN and OUT endpoints in addition to EP0. +

+Definition at line 533 of file dwc_otg_cil.h. +

+

+ +

+
+ + + + +
int32_t dwc_otg_core_params::phy_type
+
+
+ +

+Specifies the type of PHY interface to use. +

+By default, the driver will automatically detect the phy_type.

+0 - Full Speed PHY 1 - UTMI+ (default) 2 - ULPI +

+Definition at line 543 of file dwc_otg_cil.h. +

+

+ +

+ +
+ +

+Specifies the UTMI+ Data Width. +

+This parameter is applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI PHY_TYPE, this parameter indicates the data width between the MAC and the ULPI Wrapper.) Also, this parameter is applicable only if the OTG_HSPHY_WIDTH cC parameter was set to "8 and 16 bits", meaning that the core has been configured to work at either data path width.

+8 or 16 bits (default 16) +

+Definition at line 556 of file dwc_otg_cil.h. +

+

+ +

+ +
+ +

+Specifies whether the ULPI operates at double or single data rate. +

+This parameter is only applicable if PHY_TYPE is ULPI.

+0 - single data rate ULPI interface with 8 bit wide data bus (default) 1 - double data rate ULPI interface with 4 bit wide data bus +

+Definition at line 568 of file dwc_otg_cil.h. +

+

+ +

+
+ + + + +
int32_t dwc_otg_core_params::i2c_enable
+
+
+ +

+Specifies whether to use the I2Cinterface for full speed PHY. +

+This parameter is only applicable if PHY_TYPE is FS. 0 - No (default) 1 - Yes +

+Definition at line 582 of file dwc_otg_cil.h. +

+

+ +

+
+ + + + +
uint32_t dwc_otg_core_params::dev_tx_fifo_size[MAX_TX_FIFOS]
+
+
+ +

+Number of 4-byte words in each of the Tx FIFOs in device mode when dynamic FIFO sizing is enabled. +

+4 to 768 (default 256) +

+Definition at line 600 of file dwc_otg_cil.h. +

+

+


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__dma__desc.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__dma__desc.html new file mode 100644 index 000000000000..7c9468d6f4ee --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__dma__desc.html @@ -0,0 +1,50 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_dev_dma_desc Struct Reference + + + + + + +

dwc_otg_dev_dma_desc Struct Reference

DMA Descriptor structure. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + +

Data Fields

+dev_dma_desc_sts_t status
 DMA Descriptor status quadlet.
+uint32_t buf
 DMA Descriptor data buffer pointer.
+


Detailed Description

+DMA Descriptor structure. +

+DMA Descriptor structure contains two quadlets: Status quadlet and Data buffer pointer. +

+ +

+Definition at line 1542 of file dwc_otg_regs.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__global__regs.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__global__regs.html new file mode 100644 index 000000000000..ba941d9847e8 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__global__regs.html @@ -0,0 +1,441 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_dev_global_regs Struct Reference + + + + + + +

dwc_otg_dev_global_regs Struct Reference

Device Global Registers. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

volatile uint32_t dcfg
 Device Configuration Register.
volatile uint32_t dctl
 Device Control Register.
volatile uint32_t dsts
 Device Status Register (Read Only).
uint32_t unused
 Reserved.
volatile uint32_t diepmsk
 Device IN Endpoint Common Interrupt Mask Register.
volatile uint32_t doepmsk
 Device OUT Endpoint Common Interrupt Mask Register.
volatile uint32_t daint
 Device All Endpoints Interrupt Register.
volatile uint32_t daintmsk
 Device All Endpoints Interrupt Mask Register.
volatile uint32_t dtknqr1
 Device IN Token Queue Read Register-1 (Read Only).
volatile uint32_t dtknqr2
 Device IN Token Queue Read Register-2 (Read Only).
volatile uint32_t dvbusdis
 Device VBUS discharge Register.
volatile uint32_t dvbuspulse
 Device VBUS Pulse Register.
volatile uint32_t dtknqr3_dthrctl
 Device IN Token Queue Read Register-3 (Read Only).
volatile uint32_t dtknqr4_fifoemptymsk
 Device IN Token Queue Read Register-4 (Read Only).
volatile uint32_t deachint
 Device Each Endpoint Interrupt Register (Read Only).
volatile uint32_t deachintmsk
 Device Each Endpoint Interrupt mask Register (Read/Write).
volatile uint32_t diepeachintmsk [MAX_EPS_CHANNELS]
 Device Each In Endpoint Interrupt mask Register (Read/Write).
volatile uint32_t doepeachintmsk [MAX_EPS_CHANNELS]
 Device Each Out Endpoint Interrupt mask Register (Read/Write).
+


Detailed Description

+Device Global Registers. +

+Offsets 800h-BFFh

+The following structures define the size and relative field offsets for the Device Mode Registers.

+These registers are visible only in Device mode and must not be accessed in Host mode, as the results are unknown. +

+ +

+Definition at line 865 of file dwc_otg_regs.h.


Field Documentation

+ +
+
+ + + + +
volatile uint32_t dwc_otg_dev_global_regs::dcfg
+
+
+ +

+Device Configuration Register. +

+Offset 800h +

+Definition at line 867 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_global_regs::dctl
+
+
+ +

+Device Control Register. +

+Offset: 804h +

+Definition at line 869 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_global_regs::dsts
+
+
+ +

+Device Status Register (Read Only). +

+Offset: 808h +

+Definition at line 871 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
uint32_t dwc_otg_dev_global_regs::unused
+
+
+ +

+Reserved. +

+Offset: 80Ch +

+Definition at line 873 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_global_regs::diepmsk
+
+
+ +

+Device IN Endpoint Common Interrupt Mask Register. +

+Offset: 810h +

+Definition at line 876 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_global_regs::doepmsk
+
+
+ +

+Device OUT Endpoint Common Interrupt Mask Register. +

+Offset: 814h +

+Definition at line 879 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_global_regs::daint
+
+
+ +

+Device All Endpoints Interrupt Register. +

+Offset: 818h +

+Definition at line 881 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_global_regs::daintmsk
+
+
+ +

+Device All Endpoints Interrupt Mask Register. +

+Offset: 81Ch +

+Definition at line 884 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_global_regs::dtknqr1
+
+
+ +

+Device IN Token Queue Read Register-1 (Read Only). +

+Offset: 820h +

+Definition at line 887 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_global_regs::dtknqr2
+
+
+ +

+Device IN Token Queue Read Register-2 (Read Only). +

+Offset: 824h +

+Definition at line 890 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_global_regs::dvbusdis
+
+
+ +

+Device VBUS discharge Register. +

+Offset: 828h +

+Definition at line 892 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_global_regs::dvbuspulse
+
+
+ +

+Device VBUS Pulse Register. +

+Offset: 82Ch +

+Definition at line 894 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_global_regs::dtknqr3_dthrctl
+
+
+ +

+Device IN Token Queue Read Register-3 (Read Only). +

+/ Device Thresholding control register (Read/Write) Offset: 830h +

+Definition at line 898 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_global_regs::dtknqr4_fifoemptymsk
+
+
+ +

+Device IN Token Queue Read Register-4 (Read Only). +

+/ Device IN EPs empty Inr. Mask Register (Read/Write) Offset: 834h +

+Definition at line 902 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_global_regs::deachint
+
+
+ +

+Device Each Endpoint Interrupt Register (Read Only). +

+/ Offset: 838h +

+Definition at line 905 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_global_regs::deachintmsk
+
+
+ +

+Device Each Endpoint Interrupt mask Register (Read/Write). +

+/ Offset: 83Ch +

+Definition at line 908 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_global_regs::diepeachintmsk[MAX_EPS_CHANNELS]
+
+
+ +

+Device Each In Endpoint Interrupt mask Register (Read/Write). +

+/ Offset: 840h +

+Definition at line 911 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_global_regs::doepeachintmsk[MAX_EPS_CHANNELS]
+
+
+ +

+Device Each Out Endpoint Interrupt mask Register (Read/Write). +

+/ Offset: 880h +

+Definition at line 914 of file dwc_otg_regs.h. +

+

+


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__if.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__if.html new file mode 100644 index 000000000000..730e5a4acb80 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__if.html @@ -0,0 +1,142 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_dev_if Struct Reference + + + + + + +

dwc_otg_dev_if Struct Reference

The dwc_otg_dev_if structure contains information needed to manage the DWC_otg controller acting in device mode. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

dwc_otg_device_global_regs_tdev_global_regs
 Pointer to device Global registers.
+dwc_otg_dev_in_ep_regs_tin_ep_regs [MAX_EPS_CHANNELS]
 Device Logical IN Endpoint-Specific Registers 900h-AFCh.
+dwc_otg_dev_out_ep_regs_tout_ep_regs [MAX_EPS_CHANNELS]
 Device Logical OUT Endpoint-Specific Registers B00h-CFCh.
+uint8_t speed
 Device Speed 0: Unknown, 1: LS, 2:FS, 3: HS.
+uint8_t num_in_eps
 Number # of Tx EP range: 0-15 exept ep0.
+uint8_t num_out_eps
 Number # of Rx EP range: 0-15 exept ep 0.
+uint16_t perio_tx_fifo_size [MAX_PERIO_FIFOS]
 Size of periodic FIFOs (Bytes).
+uint16_t tx_fifo_size [MAX_TX_FIFOS]
 Size of Tx FIFOs (Bytes).
+uint16_t rx_thr_en
 Thresholding enable flags and length varaiables.
+uint16_t iso_tx_thr_en
+uint16_t non_iso_tx_thr_en
+uint16_t rx_thr_length
+uint16_t tx_thr_length
+dwc_dma_t dma_setup_desc_addr [2]
 2 descriptors for SETUP packets
+dwc_otg_dev_dma_desc_tsetup_desc_addr [2]
+dwc_otg_dev_dma_desc_tpsetup
 Pointer to Descriptor with latest SETUP packet.
+uint32_t setup_desc_index
 Index of current SETUP handler descriptor.
+dwc_dma_t dma_in_desc_addr
 Descriptor for Data In or Status In phases.
+dwc_otg_dev_dma_desc_tin_desc_addr
+dwc_dma_t dma_out_desc_addr
 Descriptor for Data Out or Status Out phases.
+dwc_otg_dev_dma_desc_tout_desc_addr
+uint32_t spd
 Setup Packet Detected - if set clear NAK when queueing.
+


Detailed Description

+The dwc_otg_dev_if structure contains information needed to manage the DWC_otg controller acting in device mode. +

+It represents the programming view of the device-specific aspects of the controller. +

+ +

+Definition at line 1554 of file dwc_otg_regs.h.


Field Documentation

+ +
+ +
+ +

+Pointer to device Global registers. +

+Device Global Registers starting at offset 800h +

+Definition at line 1558 of file dwc_otg_regs.h. +

+

+


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__in__ep__regs.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__in__ep__regs.html new file mode 100644 index 000000000000..62f3a60f2d1e --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__in__ep__regs.html @@ -0,0 +1,221 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_dev_in_ep_regs Struct Reference + + + + + + +

dwc_otg_dev_in_ep_regs Struct Reference

Device Logical IN Endpoint-Specific Registers. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

volatile uint32_t diepctl
 Device IN Endpoint Control Register.
uint32_t reserved04
 Reserved.
volatile uint32_t diepint
 Device IN Endpoint Interrupt Register.
uint32_t reserved0C
 Reserved.
volatile uint32_t dieptsiz
 Device IN Endpoint Transfer Size Register.
volatile uint32_t diepdma
 Device IN Endpoint DMA Address Register.
volatile uint32_t dtxfsts
 Device IN Endpoint Transmit FIFO Status Register.
volatile uint32_t diepdmab
 Device IN Endpoint DMA Buffer Register.
+


Detailed Description

+Device Logical IN Endpoint-Specific Registers. +

+Offsets 900h-AFCh

+There will be one set of endpoint registers per logical endpoint implemented.

+These registers are visible only in Device mode and must not be accessed in Host mode, as the results are unknown. +

+ +

+Definition at line 1239 of file dwc_otg_regs.h.


Field Documentation

+ +
+
+ + + + +
volatile uint32_t dwc_otg_dev_in_ep_regs::diepctl
+
+
+ +

+Device IN Endpoint Control Register. +

+Offset:900h + (ep_num * 20h) + 00h +

+Definition at line 1242 of file dwc_otg_regs.h. +

+

+ +

+ +
+ +

+Reserved. +

+Offset:900h + (ep_num * 20h) + 04h +

+Definition at line 1244 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_in_ep_regs::diepint
+
+
+ +

+Device IN Endpoint Interrupt Register. +

+Offset:900h + (ep_num * 20h) + 08h +

+Definition at line 1247 of file dwc_otg_regs.h. +

+

+ +

+ +
+ +

+Reserved. +

+Offset:900h + (ep_num * 20h) + 0Ch +

+Definition at line 1249 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_in_ep_regs::dieptsiz
+
+
+ +

+Device IN Endpoint Transfer Size Register. +

+Offset:900h + (ep_num * 20h) + 10h +

+Definition at line 1252 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_in_ep_regs::diepdma
+
+
+ +

+Device IN Endpoint DMA Address Register. +

+Offset:900h + (ep_num * 20h) + 14h +

+Definition at line 1255 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_in_ep_regs::dtxfsts
+
+
+ +

+Device IN Endpoint Transmit FIFO Status Register. +

+Offset:900h + (ep_num * 20h) + 18h +

+Definition at line 1258 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_in_ep_regs::diepdmab
+
+
+ +

+Device IN Endpoint DMA Buffer Register. +

+Offset:900h + (ep_num * 20h) + 1Ch +

+Definition at line 1261 of file dwc_otg_regs.h. +

+

+


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__out__ep__regs.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__out__ep__regs.html new file mode 100644 index 000000000000..32d4bee93344 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__dev__out__ep__regs.html @@ -0,0 +1,221 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_dev_out_ep_regs Struct Reference + + + + + + +

dwc_otg_dev_out_ep_regs Struct Reference

Device Logical OUT Endpoint-Specific Registers. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

volatile uint32_t doepctl
 Device OUT Endpoint Control Register.
volatile uint32_t doepfn
 Device OUT Endpoint Frame number Register.
volatile uint32_t doepint
 Device OUT Endpoint Interrupt Register.
uint32_t reserved0C
 Reserved.
volatile uint32_t doeptsiz
 Device OUT Endpoint Transfer Size Register.
volatile uint32_t doepdma
 Device OUT Endpoint DMA Address Register.
uint32_t unused
 Reserved.
uint32_t doepdmab
 Device OUT Endpoint DMA Buffer Register.
+


Detailed Description

+Device Logical OUT Endpoint-Specific Registers. +

+Offsets: B00h-CFCh

+There will be one set of endpoint registers per logical endpoint implemented.

+These registers are visible only in Device mode and must not be accessed in Host mode, as the results are unknown. +

+ +

+Definition at line 1274 of file dwc_otg_regs.h.


Field Documentation

+ +
+
+ + + + +
volatile uint32_t dwc_otg_dev_out_ep_regs::doepctl
+
+
+ +

+Device OUT Endpoint Control Register. +

+Offset:B00h + (ep_num * 20h) + 00h +

+Definition at line 1277 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_out_ep_regs::doepfn
+
+
+ +

+Device OUT Endpoint Frame number Register. +

+Offset: B00h + (ep_num * 20h) + 04h +

+Definition at line 1280 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_out_ep_regs::doepint
+
+
+ +

+Device OUT Endpoint Interrupt Register. +

+Offset:B00h + (ep_num * 20h) + 08h +

+Definition at line 1283 of file dwc_otg_regs.h. +

+

+ +

+ +
+ +

+Reserved. +

+Offset:B00h + (ep_num * 20h) + 0Ch +

+Definition at line 1285 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_out_ep_regs::doeptsiz
+
+
+ +

+Device OUT Endpoint Transfer Size Register. +

+Offset: B00h + (ep_num * 20h) + 10h +

+Definition at line 1288 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_dev_out_ep_regs::doepdma
+
+
+ +

+Device OUT Endpoint DMA Address Register. +

+Offset:B00h + (ep_num * 20h) + 14h +

+Definition at line 1291 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
uint32_t dwc_otg_dev_out_ep_regs::unused
+
+
+ +

+Reserved. +

+Offset:B00h + * (ep_num * 20h) + 18h +

+Definition at line 1293 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
uint32_t dwc_otg_dev_out_ep_regs::doepdmab
+
+
+ +

+Device OUT Endpoint DMA Buffer Register. +

+Offset:B00h + (ep_num * 20h) + 1Ch +

+Definition at line 1296 of file dwc_otg_regs.h. +

+

+


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__device.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__device.html new file mode 100644 index 000000000000..2a9a04a383ce --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__device.html @@ -0,0 +1,64 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_device Struct Reference + + + + + + +

dwc_otg_device Struct Reference

This structure is a wrapper that encapsulates the driver components used to manage a single DWC_otg controller. +More... +

+#include <dwc_otg_driver.h> +

+ + + + + + + + + + + + + + + + + + + + + +

Data Fields

+void * base
 Base address returned from ioremap().
+dwc_otg_core_if_tcore_if
 Pointer to the core interface structure.
+uint32_t reg_offset
 Register offset for Diagnostic API.
+dwc_otg_pcdpcd
 Pointer to the PCD structure.
+dwc_otg_hcdhcd
 Pointer to the HCD structure.
+uint8_t common_irq_installed
 Flag to indicate whether the common IRQ handler is installed.
+


Detailed Description

+This structure is a wrapper that encapsulates the driver components used to manage a single DWC_otg controller. +

+ +

+Definition at line 56 of file dwc_otg_driver.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__driver__module__params.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__driver__module__params.html new file mode 100644 index 000000000000..bf9eb57a0d8c --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__driver__module__params.html @@ -0,0 +1,146 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_driver_module_params Struct Reference + + + + + + +

dwc_otg_driver_module_params Struct Reference

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+int32_t opt
+int32_t otg_cap
+int32_t dma_enable
+int32_t dma_desc_enable
+int32_t dma_burst_size
+int32_t speed
+int32_t host_support_fs_ls_low_power
+int32_t host_ls_low_power_phy_clk
+int32_t enable_dynamic_fifo
+int32_t data_fifo_size
+int32_t dev_rx_fifo_size
+int32_t dev_nperio_tx_fifo_size
+uint32_t dev_perio_tx_fifo_size [MAX_PERIO_FIFOS]
+int32_t host_rx_fifo_size
+int32_t host_nperio_tx_fifo_size
+int32_t host_perio_tx_fifo_size
+int32_t max_transfer_size
+int32_t max_packet_count
+int32_t host_channels
+int32_t dev_endpoints
+int32_t phy_type
+int32_t phy_utmi_width
+int32_t phy_ulpi_ddr
+int32_t phy_ulpi_ext_vbus
+int32_t i2c_enable
+int32_t ulpi_fs_ls
+int32_t ts_dline
+int32_t en_multiple_tx_fifo
+uint32_t dev_tx_fifo_size [MAX_TX_FIFOS]
+uint32_t thr_ctl
+uint32_t tx_thr_length
+uint32_t rx_thr_length
+int32_t pti_enable
+int32_t mpi_enable
+int32_t lpm_enable
+int32_t ic_usb_cap
+int32_t ahb_thr_ratio
+

Detailed Description

+ +

+ +

+Definition at line 120 of file dwc_otg_driver.c.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hc__regs.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hc__regs.html new file mode 100644 index 000000000000..eaaf3527f89d --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hc__regs.html @@ -0,0 +1,200 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hc_regs Struct Reference + + + + + + +

dwc_otg_hc_regs Struct Reference

Host Channel Specific Registers. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

volatile uint32_t hcchar
 Host Channel 0 Characteristic Register.
volatile uint32_t hcsplt
 Host Channel 0 Split Control Register.
volatile uint32_t hcint
 Host Channel 0 Interrupt Register.
volatile uint32_t hcintmsk
 Host Channel 0 Interrupt Mask Register.
volatile uint32_t hctsiz
 Host Channel 0 Transfer Size Register.
volatile uint32_t hcdma
 Host Channel 0 DMA Address Register.
+volatile uint32_t reserved
volatile uint32_t hcdmab
 Host Channel 0 DMA Buffer Address Register.
+


Detailed Description

+Host Channel Specific Registers. +

+500h-5FCh +

+ +

+Definition at line 1838 of file dwc_otg_regs.h.


Field Documentation

+ +
+
+ + + + +
volatile uint32_t dwc_otg_hc_regs::hcchar
+
+
+ +

+Host Channel 0 Characteristic Register. +

+Offset: 500h + (chan_num * 20h) + 00h +

+Definition at line 1841 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_hc_regs::hcsplt
+
+
+ +

+Host Channel 0 Split Control Register. +

+Offset: 500h + (chan_num * 20h) + 04h +

+Definition at line 1843 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_hc_regs::hcint
+
+
+ +

+Host Channel 0 Interrupt Register. +

+Offset: 500h + (chan_num * 20h) + 08h +

+Definition at line 1845 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_hc_regs::hcintmsk
+
+
+ +

+Host Channel 0 Interrupt Mask Register. +

+Offset: 500h + (chan_num * 20h) + 0Ch +

+Definition at line 1847 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_hc_regs::hctsiz
+
+
+ +

+Host Channel 0 Transfer Size Register. +

+Offset: 500h + (chan_num * 20h) + 10h +

+Definition at line 1849 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_hc_regs::hcdma
+
+
+ +

+Host Channel 0 DMA Address Register. +

+Offset: 500h + (chan_num * 20h) + 14h +

+Definition at line 1851 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_hc_regs::hcdmab
+
+
+ +

+Host Channel 0 DMA Buffer Address Register. +

+Offset: 500h + (chan_num * 20h) + 1Ch +

+Definition at line 1854 of file dwc_otg_regs.h. +

+

+


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd.html new file mode 100644 index 000000000000..eee25ed84a04 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd.html @@ -0,0 +1,377 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hcd Struct Reference + + + + + + +

dwc_otg_hcd Struct Reference

This structure holds the state of the HCD, including the non-periodic and periodic schedules. +More... +

+#include <dwc_otg_hcd.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+dwc_otg_core_if_tcore_if
 DWC OTG Core Interface Layer.
+dwc_otg_hcd_function_opsfops
 Function HCD driver callbacks.
+dwc_otg_hcd::dwc_otg_hcd_internal_flags flags
 Internal DWC HCD Flags.
dwc_list_link_t non_periodic_sched_inactive
 Inactive items in the non-periodic schedule.
dwc_list_link_t non_periodic_sched_active
 Active items in the non-periodic schedule.
+dwc_list_link_t * non_periodic_qh_ptr
 Pointer to the next Queue Head to process in the active non-periodic schedule.
dwc_list_link_t periodic_sched_inactive
 Inactive items in the periodic schedule.
dwc_list_link_t periodic_sched_ready
 List of periodic QHs that are ready for execution in the next frame, but have not yet been assigned to host channels.
dwc_list_link_t periodic_sched_assigned
 List of periodic QHs to be executed in the next frame that are assigned to host channels.
dwc_list_link_t periodic_sched_queued
 List of periodic QHs that have been queued for execution.
uint16_t periodic_usecs
 Total bandwidth claimed so far for periodic transfers.
uint16_t frame_number
 Frame number read from the core at SOF.
hc_list free_hc_list
 Free host channels in the controller.
int periodic_channels
 Number of host channels assigned to periodic transfers.
+int non_periodic_channels
 Number of host channels assigned to non-periodic transfers.
dwc_hchc_ptr_array [MAX_EPS_CHANNELS]
 Array of pointers to the host channel descriptors.
uint8_t * status_buf
 Buffer to use for any data received during the status phase of a control transfer.
+dma_addr_t status_buf_dma
 DMA address for status_buf.
dwc_timer_t * conn_timer
 Connection timer.
+dwc_tasklet_t * reset_tasklet
+dwc_spinlock_t * lock
+void * priv
 Private data that could be used by OS wrapper.
+uint8_t otg_port
+uint32_t * frame_list
 Frame List.
+dma_addr_t frame_list_dma
 Frame List DMA address.

Data Structures

union  dwc_otg_hcd_internal_flags
 Internal DWC HCD Flags. More...
+


Detailed Description

+This structure holds the state of the HCD, including the non-periodic and periodic schedules. +

+ +

+Definition at line 372 of file dwc_otg_hcd.h.


Field Documentation

+ +
+
+ + + + +
dwc_list_link_t dwc_otg_hcd::non_periodic_sched_inactive
+
+
+ +

+Inactive items in the non-periodic schedule. +

+This is a list of Queue Heads. Transfers associated with these Queue Heads are not currently assigned to a host channel. +

+Definition at line 399 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + +
dwc_list_link_t dwc_otg_hcd::non_periodic_sched_active
+
+
+ +

+Active items in the non-periodic schedule. +

+This is a list of Queue Heads. Transfers associated with these Queue Heads are currently assigned to a host channel. +

+Definition at line 406 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + +
dwc_list_link_t dwc_otg_hcd::periodic_sched_inactive
+
+
+ +

+Inactive items in the periodic schedule. +

+This is a list of QHs for periodic transfers that are _not_ scheduled for the next frame. Each QH in the list has an interval counter that determines when it needs to be scheduled for execution. This scheduling mechanism allows only a simple calculation for periodic bandwidth used (i.e. must assume that all periodic transfers may need to execute in the same frame). However, it greatly simplifies scheduling and should be sufficient for the vast majority of OTG hosts, which need to connect to a small number of peripherals at one time.

+Items move from this list to periodic_sched_ready when the QH interval counter is 0 at SOF. +

+Definition at line 428 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + +
dwc_list_link_t dwc_otg_hcd::periodic_sched_ready
+
+
+ +

+List of periodic QHs that are ready for execution in the next frame, but have not yet been assigned to host channels. +

+Items move from this list to periodic_sched_assigned as host channels become available during the current frame. +

+Definition at line 437 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + +
dwc_list_link_t dwc_otg_hcd::periodic_sched_assigned
+
+
+ +

+List of periodic QHs to be executed in the next frame that are assigned to host channels. +

+Items move from this list to periodic_sched_queued as the transactions for the QH are queued to the DWC_otg controller. +

+Definition at line 446 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + +
dwc_list_link_t dwc_otg_hcd::periodic_sched_queued
+
+
+ +

+List of periodic QHs that have been queued for execution. +

+Items move from this list to either periodic_sched_inactive or periodic_sched_ready when the channel associated with the transfer is released. If the interval for the QH is 1, the item moves to periodic_sched_ready because it must be rescheduled for the next frame. Otherwise, the item moves to periodic_sched_inactive. +

+Definition at line 457 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + +
uint16_t dwc_otg_hcd::periodic_usecs
+
+
+ +

+Total bandwidth claimed so far for periodic transfers. +

+This value is in microseconds per (micro)frame. The assumption is that all periodic transfers may occur in the same (micro)frame. +

+Definition at line 464 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + +
uint16_t dwc_otg_hcd::frame_number
+
+
+ +

+Frame number read from the core at SOF. +

+The value ranges from 0 to DWC_HFNUM_MAX_FRNUM. +

+Definition at line 470 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + +
struct hc_list dwc_otg_hcd::free_hc_list
+
+
+ +

+Free host channels in the controller. +

+This is a list of dwc_hc_t items. +

+Definition at line 476 of file dwc_otg_hcd.h. +

+

+ +

+ +
+ +

+Number of host channels assigned to periodic transfers. +

+Currently assuming that there is a dedicated host channel for each periodic transaction and at least one host channel available for non-periodic transactions. +

+Definition at line 483 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + +
struct dwc_hc* dwc_otg_hcd::hc_ptr_array[MAX_EPS_CHANNELS]
+
+
+ +

+Array of pointers to the host channel descriptors. +

+Allows accessing a host channel descriptor given the host channel number. This is useful in interrupt handlers. +

+Definition at line 495 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + +
uint8_t* dwc_otg_hcd::status_buf
+
+
+ +

+Buffer to use for any data received during the status phase of a control transfer. +

+Normally no data is transferred during the status phase. This buffer is used as a bit bucket. +

+Definition at line 502 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + +
dwc_timer_t* dwc_otg_hcd::conn_timer
+
+
+ +

+Connection timer. +

+An OTG host must display a message if the device does not connect. Started when the VBus power is turned on via sysfs attribute "buspower". +

+Definition at line 515 of file dwc_otg_hcd.h. +

+

+


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd__function__ops.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd__function__ops.html new file mode 100644 index 000000000000..587487ebb0da --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd__function__ops.html @@ -0,0 +1,53 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hcd_function_ops Struct Reference + + + + + + +

dwc_otg_hcd_function_ops Struct Reference

+ + + + + + + + + + + + + + +

Data Fields

+dwc_otg_hcd_start_cb_t start
+dwc_otg_hcd_disconnect_cb_t disconnect
+dwc_otg_hcd_hub_info_from_urb_cb_t hub_info
+dwc_otg_hcd_speed_from_urb_cb_t speed
+dwc_otg_hcd_complete_urb_cb_t complete
+dwc_otg_hcd_get_b_hnp_enable get_b_hnp_enable
+

Detailed Description

+ +

+ +

+Definition at line 76 of file dwc_otg_hcd_if.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd__iso__packet__desc.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd__iso__packet__desc.html new file mode 100644 index 000000000000..6067aef325e1 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd__iso__packet__desc.html @@ -0,0 +1,47 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hcd_iso_packet_desc Struct Reference + + + + + + +

dwc_otg_hcd_iso_packet_desc Struct Reference

+ + + + + + + + + + +

Data Fields

+uint32_t offset
+uint32_t length
+uint32_t actual_length
+uint32_t status
+

Detailed Description

+ +

+ +

+Definition at line 63 of file dwc_otg_hcd.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd__pipe__info.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd__pipe__info.html new file mode 100644 index 000000000000..dd40bdad440b --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd__pipe__info.html @@ -0,0 +1,50 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hcd_pipe_info Struct Reference + + + + + + +

dwc_otg_hcd_pipe_info Struct Reference

+ + + + + + + + + + + + +

Data Fields

+uint8_t dev_addr
+uint8_t ep_num
+uint8_t pipe_type
+uint8_t pipe_dir
+uint16_t mps
+

Detailed Description

+ +

+ +

+Definition at line 55 of file dwc_otg_hcd.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd__urb.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd__urb.html new file mode 100644 index 000000000000..3cb4d1a44351 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__hcd__urb.html @@ -0,0 +1,80 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hcd_urb Struct Reference + + + + + + +

dwc_otg_hcd_urb Struct Reference

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+void * priv
+dwc_otg_qtdqtd
+void * buf
+dwc_dma_t dma
+void * setup_packet
+dwc_dma_t setup_dma
+uint32_t length
+uint32_t actual_length
+uint32_t status
+uint32_t error_count
+uint32_t packet_count
+uint32_t flags
+uint16_t interval
+dwc_otg_hcd_pipe_info pipe_info
+dwc_otg_hcd_iso_packet_desc iso_descs [0]
+

Detailed Description

+ +

+ +

+Definition at line 72 of file dwc_otg_hcd.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__host__dma__desc.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__host__dma__desc.html new file mode 100644 index 000000000000..e888f0af510c --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__host__dma__desc.html @@ -0,0 +1,50 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_host_dma_desc Struct Reference + + + + + + +

dwc_otg_host_dma_desc Struct Reference

Host-mode DMA Descriptor structure. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + +

Data Fields

+host_dma_desc_sts_t status
 DMA Descriptor status quadlet.
+uint32_t buf
 DMA Descriptor data buffer pointer.
+


Detailed Description

+Host-mode DMA Descriptor structure. +

+DMA Descriptor structure contains two quadlets: Status quadlet and Data buffer pointer. +

+ +

+Definition at line 2166 of file dwc_otg_regs.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__host__global__regs.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__host__global__regs.html new file mode 100644 index 000000000000..498888c9f71b --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__host__global__regs.html @@ -0,0 +1,219 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_host_global_regs Struct Reference + + + + + + +

dwc_otg_host_global_regs Struct Reference

The Host Global Registers structure defines the size and relative field offsets for the Host Mode Global Registers. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

volatile uint32_t hcfg
 Host Configuration Register.
volatile uint32_t hfir
 Host Frame Interval Register.
volatile uint32_t hfnum
 Host Frame Number / Frame Remaining Register.
uint32_t reserved40C
 Reserved.
volatile uint32_t hptxsts
 Host Periodic Transmit FIFO/ Queue Status Register.
volatile uint32_t haint
 Host All Channels Interrupt Register.
volatile uint32_t haintmsk
 Host All Channels Interrupt Mask Register.
volatile uint32_t hflbaddr
 Host Frame List Base Address Register .
+


Detailed Description

+The Host Global Registers structure defines the size and relative field offsets for the Host Mode Global Registers. +

+Host Global Registers offsets 400h-7FFh. +

+ +

+Definition at line 1627 of file dwc_otg_regs.h.


Field Documentation

+ +
+
+ + + + +
volatile uint32_t dwc_otg_host_global_regs::hcfg
+
+
+ +

+Host Configuration Register. +

+Offset: 400h +

+Definition at line 1629 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_host_global_regs::hfir
+
+
+ +

+Host Frame Interval Register. +

+Offset: 404h +

+Definition at line 1631 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_host_global_regs::hfnum
+
+
+ +

+Host Frame Number / Frame Remaining Register. +

+Offset: 408h +

+Definition at line 1633 of file dwc_otg_regs.h. +

+

+ +

+ +
+ +

+Reserved. +

+Offset: 40Ch +

+Definition at line 1635 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_host_global_regs::hptxsts
+
+
+ +

+Host Periodic Transmit FIFO/ Queue Status Register. +

+Offset: 410h +

+Definition at line 1637 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_host_global_regs::haint
+
+
+ +

+Host All Channels Interrupt Register. +

+Offset: 414h +

+Definition at line 1639 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_host_global_regs::haintmsk
+
+
+ +

+Host All Channels Interrupt Mask Register. +

+Offset: 418h +

+Definition at line 1641 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
volatile uint32_t dwc_otg_host_global_regs::hflbaddr
+
+
+ +

+Host Frame List Base Address Register . +

+Offset: 41Ch +

+Definition at line 1643 of file dwc_otg_regs.h. +

+

+


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__host__if.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__host__if.html new file mode 100644 index 000000000000..83ca3eccf246 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__host__if.html @@ -0,0 +1,66 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_host_if Struct Reference + + + + + + +

dwc_otg_host_if Struct Reference

OTG Host Interface Structure. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + +

Data Fields

+dwc_otg_host_global_regs_thost_global_regs
 Host Global Registers starting at offset 400h.
+volatile uint32_t * hprt0
 Host Port 0 Control and Status Register.
+dwc_otg_hc_regs_thc_regs [MAX_EPS_CHANNELS]
 Host Channel Specific Registers at offsets 500h-5FCh.
+uint8_t num_host_channels
 Number of Host Channels (range: 1-16).
+uint8_t perio_eps_supported
 Periodic EPs supported (0: no, 1: yes).
+uint16_t perio_tx_fifo_size
 Periodic Tx FIFO Size (Only 1 host periodic Tx FIFO).
+


Detailed Description

+OTG Host Interface Structure. +

+The OTG Host Interface Structure structure contains information needed to manage the DWC_otg controller acting in host mode. It represents the programming view of the host-specific aspects of the controller. +

+ +

+Definition at line 2181 of file dwc_otg_regs.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__pcd.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__pcd.html new file mode 100644 index 000000000000..996688e5db3e --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__pcd.html @@ -0,0 +1,152 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_pcd Struct Reference + + + + + + +

dwc_otg_pcd Struct Reference

DWC_otg PCD Structure. +More... +

+#include <dwc_otg_pcd.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+dwc_otg_pcd_function_opsfops
+dwc_otg_core_if_tcore_if
 Core Interface.
+ep0state_e ep0state
 State of EP0.
+unsigned ep0_pending:1
 EP0 Request is pending.
+unsigned request_config:1
 Indicates when SET CONFIGURATION Request is in process.
+unsigned remote_wakeup_enable:1
 The state of the Remote Wakeup Enable.
+unsigned b_hnp_enable:1
 The state of the B-Device HNP Enable.
+unsigned a_hnp_support:1
 The state of A-Device HNP Support.
+unsigned a_alt_hnp_support:1
 The state of the A-Device Alt HNP support.
+unsigned request_pending
 Count of pending Requests.
+union {
   usb_device_request_t   req
   uint32_t   d32 [2]
setup_pkt
 SETUP packet for EP0 This structure is allocated as a DMA buffer on PCD initialization with enough space for up to 3 setup packets.
+dwc_dma_t setup_pkt_dma_handle
+uint16_t * status_buf
 2-byte dma buffer used to return status from GET_STATUS
+dwc_dma_t status_buf_dma_handle
+dwc_otg_pcd_ep_t ep0
 EP0.
+dwc_otg_pcd_ep_t in_ep [MAX_EPS_CHANNELS-1]
 Array of IN EPs.
+dwc_otg_pcd_ep_t out_ep [MAX_EPS_CHANNELS-1]
 Array of OUT EPs.
+dwc_spinlock_t * lock
 number of valid EPs in the above array.
dwc_timer_t * srp_timer
 Timer for SRP.
+dwc_tasklet_t * test_mode_tasklet
 Tasklet to defer starting of TEST mode transmissions until Status Phase has been completed.
+dwc_tasklet_t * start_xfer_tasklet
 Tasklet to delay starting of xfer in DMA mode.
+unsigned test_mode
 The test mode to enter when the tasklet is executed.
+


Detailed Description

+DWC_otg PCD Structure. +

+This structure encapsulates the data for the dwc_otg PCD. +

+ +

+Definition at line 137 of file dwc_otg_pcd.h.


Field Documentation

+ +
+
+ + + + +
dwc_timer_t* dwc_otg_pcd::srp_timer
+
+
+ +

+Timer for SRP. +

+If it expires before SRP is successful clear the SRP. +

+Definition at line 185 of file dwc_otg_pcd.h. +

+

+


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__pcd__ep.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__pcd__ep.html new file mode 100644 index 000000000000..fed4ce3043fb --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__pcd__ep.html @@ -0,0 +1,77 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_pcd_ep Struct Reference + + + + + + +

dwc_otg_pcd_ep Struct Reference

PCD EP structure. +More... +

+#include <dwc_otg_pcd.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+const usb_endpoint_descriptor_t * desc
 USB EP Descriptor.
+req_list queue
 queue of dwc_otg_pcd_requests.
+unsigned stopped:1
+unsigned disabling:1
+unsigned dma:1
+unsigned queue_sof:1
+void * iso_req_handle
 ISOC req handle passed.
+dwc_ep_t dwc_ep
 DWC_otg ep data.
+dwc_otg_pcdpcd
 Pointer to PCD.
+void * priv
+


Detailed Description

+PCD EP structure. +

+This structure describes an EP, there is an array of EPs in the PCD structure. +

+ +

+Definition at line 109 of file dwc_otg_pcd.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__pcd__function__ops.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__pcd__function__ops.html new file mode 100644 index 000000000000..711d0e5cd39f --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__pcd__function__ops.html @@ -0,0 +1,73 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_pcd_function_ops Struct Reference + + + + + + +

dwc_otg_pcd_function_ops Struct Reference

Function Driver Ops Data Structure. +More... +

+#include <dwc_otg_pcd_if.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+dwc_connect_cb_t connect
+dwc_disconnect_cb_t disconnect
+dwc_setup_cb_t setup
+dwc_completion_cb_t complete
+dwc_isoc_completion_cb_t isoc_complete
+dwc_suspend_cb_t suspend
+dwc_sleep_cb_t sleep
+dwc_resume_cb_t resume
+dwc_reset_cb_t reset
+dwc_hnp_params_changed_cb_t hnp_changed
+cfi_setup_cb_t cfi_setup
+


Detailed Description

+Function Driver Ops Data Structure. +

+ +

+Definition at line 107 of file dwc_otg_pcd_if.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__pcd__request.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__pcd__request.html new file mode 100644 index 000000000000..d09628179ff4 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__pcd__request.html @@ -0,0 +1,64 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_pcd_request Struct Reference + + + + + + +

dwc_otg_pcd_request Struct Reference

DWC_otg request structure. +More... +

+#include <dwc_otg_pcd.h> +

+ + + + + + + + + + + + + + + + + + +

Public Member Functions

DWC_CIRCLEQ_ENTRY (dwc_otg_pcd_request) queue_entry

Data Fields

+void * priv
+void * buf
+dwc_dma_t dma
+uint32_t length
+uint32_t actual
+unsigned sent_zlp:1
+


Detailed Description

+DWC_otg request structure. +

+This structure is a list of requests. +

+ +

+Definition at line 92 of file dwc_otg_pcd.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__qh.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__qh.html new file mode 100644 index 000000000000..0e4c1697887c --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__qh.html @@ -0,0 +1,228 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_qh Struct Reference + + + + + + +

dwc_otg_qh Struct Reference

A Queue Head (QH) holds the static characteristics of an endpoint and maintains a list of transfers (QTDs) for that endpoint. +More... +

+#include <dwc_otg_hcd.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

uint8_t ep_type
 Endpoint type.
+uint8_t ep_is_in
+uint16_t maxp
 wMaxPacketSize Field of Endpoint Descriptor.
uint8_t dev_speed
 Device speed.
uint8_t data_toggle
 Determines the PID of the next data packet for non-control transfers.
+uint8_t ping_state
 Ping state if 1.
+dwc_otg_qtd_list qtd_list
 List of QTDs for this QH.
+dwc_hcchannel
 Host channel currently processing transfers for this QH.
+uint8_t do_split
 Full/low speed endpoint on high-speed hub requires split.
+uint8_t * dw_align_buf
 Used instead of original buffer if it(physical address) is not dword-aligned.
+dwc_dma_t dw_align_buf_dma
+dwc_list_link_t qh_list_entry
 Entry for QH in either the periodic or non-periodic schedule.
Periodic schedule information
+uint16_t usecs
 Bandwidth in microseconds per (micro)frame.
+uint16_t interval
 Interval between transfers in (micro)frames.
uint16_t sched_frame
 (micro)frame to initialize a periodic transfer.
+uint16_t start_split_frame
 (micro)frame at which last start split was initialized.
Descriptor DMA support
+dwc_otg_host_dma_desc_tdesc_list
 Descriptor List.
+dwc_dma_t desc_list_dma
 Descriptor List physical address.
uint32_t * n_bytes
 Xfer Bytes array.
+uint16_t ntd
 Actual number of transfer descriptors in a list.
+uint8_t td_first
 First activated isochronous transfer descriptor index.
+uint8_t td_last
 Last activated isochronous transfer descriptor index.
+


Detailed Description

+A Queue Head (QH) holds the static characteristics of an endpoint and maintains a list of transfers (QTDs) for that endpoint. +

+A QH structure may be entered in either the non-periodic or periodic schedule. +

+ +

+Definition at line 261 of file dwc_otg_hcd.h.


Field Documentation

+ +
+
+ + + + +
uint8_t dwc_otg_qh::ep_type
+
+
+ +

+Endpoint type. +

+One of the following values:

    +
  • UE_CONTROL
  • UE_BULK
  • UE_INTERRUPT
  • UE_ISOCHRONOUS
+ +

+Definition at line 270 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + +
uint8_t dwc_otg_qh::dev_speed
+
+
+ +

+Device speed. +

+One of the following values:

    +
  • DWC_OTG_EP_SPEED_LOW
  • DWC_OTG_EP_SPEED_FULL
  • DWC_OTG_EP_SPEED_HIGH
+ +

+Definition at line 283 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + +
uint8_t dwc_otg_qh::data_toggle
+
+
+ +

+Determines the PID of the next data packet for non-control transfers. +

+Ignored for control transfers.
+ One of the following values:

    +
  • DWC_OTG_HC_PID_DATA0
  • DWC_OTG_HC_PID_DATA1
+ +

+Definition at line 292 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + +
uint16_t dwc_otg_qh::sched_frame
+
+
+ +

+(micro)frame to initialize a periodic transfer. +

+The transfer executes in the following (micro)frame. +

+Definition at line 321 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + +
uint32_t* dwc_otg_qh::n_bytes
+
+
+ +

+Xfer Bytes array. +

+Each element corresponds to a descriptor and indicates original XferSize size value for the descriptor. +

+Definition at line 352 of file dwc_otg_hcd.h. +

+

+


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__qtd.html b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__qtd.html new file mode 100644 index 000000000000..9c6f130a0f91 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structdwc__otg__qtd.html @@ -0,0 +1,157 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_qtd Struct Reference + + + + + + +

dwc_otg_qtd Struct Reference

A Queue Transfer Descriptor (QTD) holds the state of a bulk, control, interrupt, or isochronous transfer. +More... +

+#include <dwc_otg_hcd.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

DWC_CIRCLEQ_ENTRY (dwc_otg_qtd) qtd_list_entry
 This list of QTDs.

Data Fields

uint8_t data_toggle
 Determines the PID of the next data packet for the data phase of control transfers.
+dwc_otg_control_phase_e control_phase
 Current phase for control transfers (Setup, Data, or Status).
+uint8_t complete_split
 Keep track of the current split type for FS/LS endpoints on a HS Hub.
+uint32_t ssplit_out_xfer_count
 How many bytes transferred during SSPLIT OUT.
+uint8_t error_count
 Holds the number of bus errors that have occurred for a transaction within this transfer.
uint16_t isoc_frame_index
 Index of the next frame descriptor for an isochronous transfer.
+uint8_t isoc_split_pos
 Position of the ISOC split on full/low speed.
+uint16_t isoc_split_offset
 Position of the ISOC split in the buffer for the current frame.
+dwc_otg_hcd_urburb
 URB for this transfer.
+dwc_otg_qhqh
+uint8_t in_process
 Indicates if this QTD is currently processed by HW.
+uint8_t n_desc
 Number of DMA descriptors for this QTD.
uint16_t isoc_frame_index_last
 Last activated frame(packet) index.
+


Detailed Description

+A Queue Transfer Descriptor (QTD) holds the state of a bulk, control, interrupt, or isochronous transfer. +

+A single QTD is created for each URB (of one of these types) submitted to the HCD. The transfer associated with a QTD may require one or multiple transactions.

+A QTD is linked to a Queue Head, which is entered in either the non-periodic or periodic schedule for execution. When a QTD is chosen for execution, some or all of its transactions may be executed. After execution, the state of the QTD is updated. The QTD may be retired if all its transactions are complete or if an error occurred. Otherwise, it remains in the schedule so more transactions can be executed later. +

+ +

+Definition at line 191 of file dwc_otg_hcd.h.


Field Documentation

+ +
+
+ + + + +
uint8_t dwc_otg_qtd::data_toggle
+
+
+ +

+Determines the PID of the next data packet for the data phase of control transfers. +

+Ignored for other transfer types.
+ One of the following values:

    +
  • DWC_OTG_HC_PID_DATA0
  • DWC_OTG_HC_PID_DATA1
+ +

+Definition at line 199 of file dwc_otg_hcd.h. +

+

+ +

+
+ + + + +
uint16_t dwc_otg_qtd::isoc_frame_index
+
+
+ +

+Index of the next frame descriptor for an isochronous transfer. +

+A frame descriptor describes the buffer position and length of the data to be transferred in the next scheduled (micro)frame of an isochronous transfer. It also holds status for that transaction. The frame index starts at 0. +

+Definition at line 224 of file dwc_otg_hcd.h. +

+

+ +

+ +
+ +

+Last activated frame(packet) index. +

+Used in Descriptor DMA mode only. +

+Definition at line 250 of file dwc_otg_hcd.h. +

+

+


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structgadget__wrapper.html b/drivers/usb/host/dwc_otg/doc/html/structgadget__wrapper.html new file mode 100644 index 000000000000..fbb5e8bc7943 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structgadget__wrapper.html @@ -0,0 +1,53 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: gadget_wrapper Struct Reference + + + + + + +

gadget_wrapper Struct Reference

+ + + + + + + + + + + + + + +

Data Fields

+dwc_otg_pcd_tpcd
+usb_gadget gadget
+usb_gadget_driver * driver
+usb_ep ep0
+usb_ep in_ep [16]
+usb_ep out_ep [16]
+

Detailed Description

+ +

+ +

+Definition at line 82 of file dwc_otg_pcd_linux.c.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structiso__pkt__info.html b/drivers/usb/host/dwc_otg/doc/html/structiso__pkt__info.html new file mode 100644 index 000000000000..5cf3c97f3787 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structiso__pkt__info.html @@ -0,0 +1,49 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: iso_pkt_info Struct Reference + + + + + + +

iso_pkt_info Struct Reference

Information for each ISOC packet. +More... +

+#include <dwc_otg_cil.h> +

+ + + + + + + + + +

Data Fields

+uint32_t offset
+uint32_t length
+int32_t status
+


Detailed Description

+Information for each ISOC packet. +

+ +

+Definition at line 77 of file dwc_otg_cil.h.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structwrapper__priv__data.html b/drivers/usb/host/dwc_otg/doc/html/structwrapper__priv__data.html new file mode 100644 index 000000000000..4bb779e0e304 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structwrapper__priv__data.html @@ -0,0 +1,38 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: wrapper_priv_data Struct Reference + + + + + + +

wrapper_priv_data Struct Reference

+ + + + +

Data Fields

+dwc_otg_hcd_tdwc_otg_hcd
+

Detailed Description

+ +

+ +

+Definition at line 95 of file dwc_otg_hcd_linux.c.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/structzero__dev.html b/drivers/usb/host/dwc_otg/doc/html/structzero__dev.html new file mode 100644 index 000000000000..3c565be289a4 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/structzero__dev.html @@ -0,0 +1,56 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: zero_dev Struct Reference + + + + + + +

zero_dev Struct Reference

+ + + + + + + + + + + + + + + + +

Data Fields

+spinlock_t lock
+usb_gadget * gadget
+usb_request * req
+u8 config
+usb_ep * in_ep
+usb_ep * out_ep
+timer_list resume
+

Detailed Description

+ +

+ +

+Definition at line 342 of file dummy_audio.c.


The documentation for this struct was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/tabs.css b/drivers/usb/host/dwc_otg/doc/html/tabs.css new file mode 100644 index 000000000000..a61552a67ad2 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/tabs.css @@ -0,0 +1,102 @@ +/* tabs styles, based on http://www.alistapart.com/articles/slidingdoors */ + +DIV.tabs +{ + float : left; + width : 100%; + background : url("tab_b.gif") repeat-x bottom; + margin-bottom : 4px; +} + +DIV.tabs UL +{ + margin : 0px; + padding-left : 10px; + list-style : none; +} + +DIV.tabs LI, DIV.tabs FORM +{ + display : inline; + margin : 0px; + padding : 0px; +} + +DIV.tabs FORM +{ + float : right; +} + +DIV.tabs A +{ + float : left; + background : url("tab_r.gif") no-repeat right top; + border-bottom : 1px solid #84B0C7; + font-size : x-small; + font-weight : bold; + text-decoration : none; +} + +DIV.tabs A:hover +{ + background-position: 100% -150px; +} + +DIV.tabs A:link, DIV.tabs A:visited, +DIV.tabs A:active, DIV.tabs A:hover +{ + color: #1A419D; +} + +DIV.tabs SPAN +{ + float : left; + display : block; + background : url("tab_l.gif") no-repeat left top; + padding : 5px 9px; + white-space : nowrap; +} + +DIV.tabs INPUT +{ + float : right; + display : inline; + font-size : 1em; +} + +DIV.tabs TD +{ + font-size : x-small; + font-weight : bold; + text-decoration : none; +} + + + +/* Commented Backslash Hack hides rule from IE5-Mac \*/ +DIV.tabs SPAN {float : none;} +/* End IE5-Mac hack */ + +DIV.tabs A:hover SPAN +{ + background-position: 0% -150px; +} + +DIV.tabs LI#current A +{ + background-position: 100% -150px; + border-width : 0px; +} + +DIV.tabs LI#current SPAN +{ + background-position: 0% -150px; + padding-bottom : 6px; +} + +DIV.nav +{ + background : none; + border : none; + border-bottom : 1px solid #84B0C7; +} diff --git a/drivers/usb/host/dwc_otg/doc/html/todo.html b/drivers/usb/host/dwc_otg/doc/html/todo.html new file mode 100644 index 000000000000..88706b0729ed --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/todo.html @@ -0,0 +1,262 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: Todo List + + + + + +

Todo List

+
Global DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW
+
Add code to initiate the HNP.
+
+

+

+
Global srp_show
+
Add code to initiate the SRP.
+
+

+

+
Global buspower_show
+
Need to do more for power on/off?
+
+

+

+
Global bussuspend_show
+
Need to do more for suspend?
+
+

+

+
Global dwc_otg_enable_device_interrupts
+
NGS: Should this be a module parameter?
+
+

+

+
Global dwc_otg_core_dev_init
+
NGS: Fix Periodic FIFO Sizing!
+
+

+

+
Global dwc_otg_core_dev_init
+
Finish debug of this
+
+

+

+
Global dwc_otg_core_dev_init
+
- if the condition needed to be checked or in any case all pending interrutps should be cleared?
+
+

+

+
Global dwc_otg_ep0_continue_transfer
+
Should there be check for room in the Tx Status Queue. If not remove the code above this comment.
+
+

+

+
Global dwc_otg_ep_write_packet
+
NGS Where are the Periodic Tx FIFO addresses intialized? What should this be?
+
+

+

+
Global dwc_otg_read_packet
+
Account for the case where _dest is not dword aligned. This requires reading data from the FIFO into a uint32_t temp buffer, then moving it into the data buffer.
+
+

+

+
Global dwc_otg_handle_disconnect_intr
+
Consolidate this if statement.
+
+

+

+
Global dwc_otg_read_common_intr
+
: The port interrupt occurs while in device mode. Added code to CIL to clear the interrupt for now!
+
+

+

+
Global MODULE_PARM_DESC
+
Set the max to 512K, modify checks
+
+

+

+
Global dwc_otg_hcd_handle_intr
+
Implement i2cintr handler.
+
+

+

+
Global dwc_otg_hcd_qh_create
+
add memflags argument
+
+

+

+
Global dwc_otg_hcd_complete_xfer_ddma
+
Consider the case when period exceeds FrameList size. Frame Rollover interrupt should be used.
+
+

+

+
Global handle_hc_nyet_intr
+
add support for isoc release
+
+

+

+
Global handle_hc_chhltd_intr_dma
+
This is here because of a possible hardware bug. Spec says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT interrupt w/ACK bit set should occur, but I only see the XFERCOMP bit, even with it masked out. This is a workaround for that behavior. Should fix this when hardware is fixed.
+
+

+

+
Global qh_init
+
Account for split transfers in the bus time.
+
+

+

+
File dwc_otg_pcd.c
+
Add Device Mode test modes (Test J mode, Test K mode, etc).

+Does it work when the request size is greater than DEPTSIZ transfer size

+

+
+

+

+
Global dwc_otg_pcd_iso_ep_start
+
- pattern data support is to be implemented in the future
+
+

+

+
Global dwc_otg_pcd_reinit
+
NGS: Add direction to EP, based on contents of HWCFG1. Need a copy of HWCFG1 in pcd structure? sprintf(";r
+
+

+

+
Global dwc_otg_pcd_reinit
+
NGS: Add direction to EP, based on contents of HWCFG1. Need a copy of HWCFG1 in pcd structure? sprintf(";r
+
+

+

+
Global dwc_otg_pcd_ep_queue
+
NGS Create a function for this.
+
+

+

+
Global do_test_mode
+
This has not been tested since the tasklet struct was put into the PCD struct!

+

+
+

+

+
Global dwc_otg_pcd_handle_rx_status_q_level_intr
+
NGS Check for buffer overflow?
+
+

+

+
Global get_ep_of_last_in_token
+
Find a simpler way to calculate the max queue position.
+
+

+

+
Global dwc_otg_pcd_stop
+
NGS Flush Periodic FIFOs
+
+

+

+
Global ep0_out_start
+
NGS: Update the comments from the HW FS.

+

+
+

+

+
Global ep0_out_start
+
dma needs to handle multiple setup packets (up to 3)
+
+

+

+
Global do_gadget_setup
+
This is a g_file_storage gadget driver specific workaround: a DELAYED_STATUS result from the fsg_setup routine will result in the gadget queueing a EP0 IN status phase for a two-stage control transfer. Exactly the same as a SET_CONFIGURATION/SET_INTERFACE except that this is a class specific request. Need a generic way to know when the gadget driver will queue the status phase. Can we assume when we call the gadget driver setup() function that it will always queue and require the following flag? Need to look into this.
+
+

+

+
Global pcd_clear_halt
+
FIXME: this causes an EP mismatch in DMA mode. epmismatch not yet implemented.
+
+

+

+
Global do_get_status
+
check for EP stall
+
+

+

+
Global do_set_feature
+
This has not been tested since the tasklet struct was put into the PCD struct!
+
+

+

+
Global do_set_feature
+
Is the gotgctl.devhnpen cleared by a USB Reset?
+
+

+

+
Global do_clear_feature
+
Add CLEAR_FEATURE for TEST modes.
+
+

+

+
Global pcd_setup
+
handle > 1 setup packet , assert error for now
+
+

+

+
Global pcd_setup
+
NGS: Handle bad setup packet?
+
+

+

+
Global handle_in_ep_timeout_intr
+
NGS Check EP type. Implement for Periodic EPs
+
+

+

+
Global handle_in_ep_nak_intr
+
implement ISR
+
+

+

+
Global handle_out_ep_babble_intr
+
implement ISR
+
+

+

+
Global handle_out_ep_nak_intr
+
implement ISR
+
+

+

+
Global handle_out_ep_nyet_intr
+
implement ISR
+
+

+

+
Global gadget_add_eps
+
NGS: What should the max packet size be set to here? Before EP type is set?
+
+

+

+
Global gadget_add_eps
+
NGS: What should the max packet size be set to here? Before EP type is set?
+
+

+

+
Global gadget_add_eps
+
NGS: What should the max packet size be set to here? Before EP type is set?
+
+

+

+
Global dwc_otg_pcd_gadget_release
+
Should this do something? Should it free the PCD?
+
+
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/tree.html b/drivers/usb/host/dwc_otg/doc/html/tree.html new file mode 100644 index 000000000000..795be4c19b1a --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/tree.html @@ -0,0 +1,201 @@ + + + + + + + TreeView + + + + +
+

DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver

+
+

o+Data Structures

+
+

|o*_ddma_align_buffer_setup

+

|o*_ddma_concat_buffer_setup

+

|o*_ddma_concat_buffer_setup_hdr

+

|o*_ddma_sg_buffer_setup

+

|o*_rx_fifo_size_setup

+

|o*_tx_fifo_size_setup

+

|o*cfi_all_features_header

+

|o*cfi_dma_buff

+

|o*cfi_ep

+

|o*cfi_feature_desc_header

+

|o*cfi_ops

+

|o*cfi_string

+

|o*cfi_usb_ctrlrequest

+

|o*cfiobject

+

|o*daint_data

+

|o*dcfg_data

+

|o*dctl_data

+

|o*depctl_data

+

|o*deptsiz0_data

+

|o*deptsiz_data

+

|o*dev_dma_desc_sts

+

|o*device_grxsts_data

+

|o*diepint_data

+

|o*doepint_data

+

|o*dsts_data

+

|o*dthrctl_data

+

|o*dtknq1_data

+

|o*dtxfsts_data

+

|o*dwc_ep

+

|o*dwc_hc

+

|o*dwc_otg_cil_callbacks

+

|o*dwc_otg_core_global_regs

+

|o*dwc_otg_core_if

+

|o*dwc_otg_core_params

+

|o*dwc_otg_dev_dma_desc

+

|o*dwc_otg_dev_global_regs

+

|o*dwc_otg_dev_if

+

|o*dwc_otg_dev_in_ep_regs

+

|o*dwc_otg_dev_out_ep_regs

+

|o*dwc_otg_device

+

|o*dwc_otg_driver_module_params

+

|o*dwc_otg_hc_regs

+

|o*dwc_otg_hcd

+

|o*dwc_otg_hcd::dwc_otg_hcd_internal_flags

+

|o*dwc_otg_hcd_function_ops

+

|o*dwc_otg_hcd_iso_packet_desc

+

|o*dwc_otg_hcd_pipe_info

+

|o*dwc_otg_hcd_urb

+

|o*dwc_otg_host_dma_desc

+

|o*dwc_otg_host_global_regs

+

|o*dwc_otg_host_if

+

|o*dwc_otg_pcd

+

|o*dwc_otg_pcd_ep

+

|o*dwc_otg_pcd_function_ops

+

|o*dwc_otg_pcd_request

+

|o*dwc_otg_qh

+

|o*dwc_otg_qtd

+

|o*fifosize_data

+

|o*gadget_wrapper

+

|o*gahbcfg_data

+

|o*gi2cctl_data

+

|o*gintmsk_data

+

|o*gintsts_data

+

|o*glpmctl_data

+

|o*gnptxsts_data

+

|o*gotgctl_data

+

|o*gotgint_data

+

|o*grstctl_data

+

|o*gusbcfg_data

+

|o*haint_data

+

|o*haintmsk_data

+

|o*hcchar_data

+

|o*hcdma_data

+

|o*hcfg_data

+

|o*hcint_data

+

|o*hcintmsk_data

+

|o*hcsplt_data

+

|o*hctsiz_data

+

|o*hfir_data

+

|o*hfnum_data

+

|o*host_dma_desc_sts

+

|o*host_grxsts_data

+

|o*hprt0_data

+

|o*hptxsts_data

+

|o*hwcfg1_data

+

|o*hwcfg2_data

+

|o*hwcfg3_data

+

|o*hwcfg4_data

+

|o*iso_pkt_info

+

|o*pcgcctl_data

+

|o*wrapper_priv_data

+

|\*zero_dev

+
+

o*Data Fields

+

o+File List

+ +

o*Globals

+

\+Related Pages

+ +
+
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniondaint__data.html b/drivers/usb/host/dwc_otg/doc/html/uniondaint__data.html new file mode 100644 index 000000000000..f83b15f309b9 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniondaint__data.html @@ -0,0 +1,131 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: daint_data Union Reference + + + + + + +

daint_data Union Reference

This union represents the bit fields in the Device All EP Interrupt and Mask Registers. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   in:16
 IN Endpoint bits.
   unsigned   out:16
 OUT Endpoint bits.
ep
 register bits
+struct {
   unsigned   inep0:1
 IN Endpoint bits.
   unsigned   inep1:1
   unsigned   inep2:1
   unsigned   inep3:1
   unsigned   inep4:1
   unsigned   inep5:1
   unsigned   inep6:1
   unsigned   inep7:1
   unsigned   inep8:1
   unsigned   inep9:1
   unsigned   inep10:1
   unsigned   inep11:1
   unsigned   inep12:1
   unsigned   inep13:1
   unsigned   inep14:1
   unsigned   inep15:1
   unsigned   outep0:1
 OUT Endpoint bits.
   unsigned   outep1:1
   unsigned   outep2:1
   unsigned   outep3:1
   unsigned   outep4:1
   unsigned   outep5:1
   unsigned   outep6:1
   unsigned   outep7:1
   unsigned   outep8:1
   unsigned   outep9:1
   unsigned   outep10:1
   unsigned   outep11:1
   unsigned   outep12:1
   unsigned   outep13:1
   unsigned   outep14:1
   unsigned   outep15:1
b
+


Detailed Description

+This union represents the bit fields in the Device All EP Interrupt and Mask Registers. +

+

    +
  • Read the register into the d32 member then set/clear the bits using the bit elements.
+ +

+ +

+Definition at line 1130 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniondcfg__data.html b/drivers/usb/host/dwc_otg/doc/html/uniondcfg__data.html new file mode 100644 index 000000000000..42d30f27c13b --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniondcfg__data.html @@ -0,0 +1,74 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dcfg_data Union Reference + + + + + + +

dcfg_data Union Reference

This union represents the bit fields in the Device Configuration Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   devspd:2
 Device Speed.
   unsigned   nzstsouthshk:1
 Non Zero Length Status OUT Handshake.
   unsigned   reserved3:1
   unsigned   devaddr:7
 Device Addresses.
   unsigned   perfrint:2
 Periodic Frame Interval.
   unsigned   reserved13_17:5
   unsigned   epmscnt:5
 In Endpoint Mis-match count.
   unsigned   descdma:1
 Enable Descriptor DMA in Device mode.
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Device Configuration Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. Write the d32 member to the dcfg register. +

+ +

+Definition at line 923 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniondctl__data.html b/drivers/usb/host/dwc_otg/doc/html/uniondctl__data.html new file mode 100644 index 000000000000..c403ec030668 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniondctl__data.html @@ -0,0 +1,96 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dctl_data Union Reference + + + + + + +

dctl_data Union Reference

This union represents the bit fields in the Device Control Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   rmtwkupsig:1
 Remote Wakeup.
   unsigned   sftdiscon:1
 Soft Disconnect.
   unsigned   gnpinnaksts:1
 Global Non-Periodic IN NAK Status.
   unsigned   goutnaksts:1
 Global OUT NAK Status.
   unsigned   tstctl:3
 Test Control.
   unsigned   sgnpinnak:1
 Set Global Non-Periodic IN NAK.
   unsigned   cgnpinnak:1
 Clear Global Non-Periodic IN NAK.
   unsigned   sgoutnak:1
 Set Global OUT NAK.
   unsigned   cgoutnak:1
 Clear Global OUT NAK.
   unsigned   pwronprgdone:1
 Power-On Programming Done.
   unsigned   gcontbna:1
 Global Continue on BNA.
   unsigned   gmc:2
 Global Multi Count.
   unsigned   ifrmnum:1
 Ignore Frame Number for ISOC EPs.
   unsigned   nakonbble:1
 NAK on Babble.
   unsigned   reserved17_31:15
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Device Control Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. +

+ +

+Definition at line 957 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniondepctl__data.html b/drivers/usb/host/dwc_otg/doc/html/uniondepctl__data.html new file mode 100644 index 000000000000..78a42437ce0a --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniondepctl__data.html @@ -0,0 +1,139 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: depctl_data Union Reference + + + + + + +

depctl_data Union Reference

This union represents the bit fields in the Device EP Control Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   mps:11
 Maximum Packet Size IN/OUT EPn IN/OUT EP0 - 2 bits 2'b00: 64 Bytes 2'b01: 32 2'b10: 16 2'b11: 8.
   unsigned   nextep:4
 Next Endpoint IN EPn/IN EP0 OUT EPn/OUT EP0 - reserved.
   unsigned   usbactep:1
 USB Active Endpoint.
   unsigned   dpid:1
 Endpoint DPID (INTR/Bulk IN and OUT endpoints) This field contains the PID of the packet going to be received or transmitted on this endpoint.
   unsigned   naksts:1
 NAK Status.
   unsigned   eptype:2
 Endpoint Type 2'b00: Control 2'b01: Isochronous 2'b10: Bulk 2'b11: Interrupt.
   unsigned   snp:1
 Snoop Mode OUT EPn/OUT EP0 IN EPn/IN EP0 - reserved.
   unsigned   stall:1
 Stall Handshake.
   unsigned   txfnum:4
 Tx Fifo Number IN EPn/IN EP0 OUT EPn/OUT EP0 - reserved.
   unsigned   cnak:1
 Clear NAK.
   unsigned   snak:1
 Set NAK.
   unsigned   setd0pid:1
 Set DATA0 PID (INTR/Bulk IN and OUT endpoints) Writing to this field sets the Endpoint DPID (DPID) field in this register to DATA0.
   unsigned   setd1pid:1
 Set DATA1 PID (INTR/Bulk IN and OUT endpoints) Writing to this field sets the Endpoint DPID (DPID) field in this register to DATA1 Set Odd (micro)frame (SetOddFr) (ISO IN and OUT Endpoints) Writing to this field sets the Even/Odd (micro)frame (EO_FrNum) field to odd (micro) frame.
   unsigned   epdis:1
 Endpoint Disable.
   unsigned   epena:1
 Endpoint Enable.
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Device EP Control Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. +

+ +

+Definition at line 1304 of file dwc_otg_regs.h.


Field Documentation

+ +
+
+ + + + +
unsigned depctl_data::dpid
+
+
+ +

+Endpoint DPID (INTR/Bulk IN and OUT endpoints) This field contains the PID of the packet going to be received or transmitted on this endpoint. +

+The application should program the PID of the first packet going to be received or transmitted on this endpoint , after the endpoint is activated. Application use the SetD1PID and SetD0PID fields of this register to program either D0 or D1 PID.

+The encoding for this field is

    +
  • 0: D0
  • 1: D1
+ +

+Definition at line 1344 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
unsigned depctl_data::setd0pid
+
+
+ +

+Set DATA0 PID (INTR/Bulk IN and OUT endpoints) Writing to this field sets the Endpoint DPID (DPID) field in this register to DATA0. +

+Set Even (micro)frame (SetEvenFr) (ISO IN and OUT Endpoints) Writing to this field sets the Even/Odd (micro)frame (EO_FrNum) field to even (micro) frame. +

+Definition at line 1381 of file dwc_otg_regs.h. +

+

+


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniondeptsiz0__data.html b/drivers/usb/host/dwc_otg/doc/html/uniondeptsiz0__data.html new file mode 100644 index 000000000000..e937961410b1 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniondeptsiz0__data.html @@ -0,0 +1,69 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: deptsiz0_data Union Reference + + + + + + +

deptsiz0_data Union Reference

This union represents the bit fields in the Device EP 0 Transfer Size Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   xfersize:7
 Transfer size.
   unsigned   reserved7_18:12
 Reserved.
   unsigned   pktcnt:1
 Packet Count.
   unsigned   reserved20_28:9
 Reserved.
   unsigned   supcnt:2
 Setup Packet Count (DOEPTSIZ0 Only).
   unsigned   reserved31
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Device EP 0 Transfer Size Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. +

+ +

+Definition at line 1423 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniondeptsiz__data.html b/drivers/usb/host/dwc_otg/doc/html/uniondeptsiz__data.html new file mode 100644 index 000000000000..1e89a244fc75 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniondeptsiz__data.html @@ -0,0 +1,63 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: deptsiz_data Union Reference + + + + + + +

deptsiz_data Union Reference

This union represents the bit fields in the Device EP Transfer Size Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   xfersize:19
 Transfer size.
   unsigned   pktcnt:10
 Packet Count.
   unsigned   mc:2
 Multi Count - Periodic IN endpoints.
   unsigned   reserved:1
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Device EP Transfer Size Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. +

+ +

+Definition at line 1403 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniondev__dma__desc__sts.html b/drivers/usb/host/dwc_otg/doc/html/uniondev__dma__desc__sts.html new file mode 100644 index 000000000000..ba4db0f3b0f4 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniondev__dma__desc__sts.html @@ -0,0 +1,140 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dev_dma_desc_sts Union Reference + + + + + + +

dev_dma_desc_sts Union Reference

This union represents the bit fields in the DMA Descriptor status quadlet. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   bytes:16
 Received number of bytes.
   unsigned   reserved16_22:7
   unsigned   mtrf:1
 Multiple Transfer - only for OUT EPs.
   unsigned   sr:1
 Setup Packet received - only for OUT EPs.
   unsigned   ioc:1
 Interrupt On Complete.
   unsigned   sp:1
 Short Packet.
   unsigned   l:1
 Last.
   unsigned   sts:2
 Receive Status.
   unsigned   bs:2
 Buffer Status.
b
 quadlet bits
+struct {
   unsigned   rxbytes:11
 Received number of bytes.
   unsigned   reserved11:1
   unsigned   framenum:11
 Frame Number.
   unsigned   pid:2
 Received ISO Data PID.
   unsigned   ioc:1
 Interrupt On Complete.
   unsigned   sp:1
 Short Packet.
   unsigned   l:1
 Last.
   unsigned   rxsts:2
 Receive Status.
   unsigned   bs:2
 Buffer Status.
b_iso_out
 iso out quadlet bits
+struct {
   unsigned   txbytes:12
 Transmited number of bytes.
   unsigned   framenum:11
 Frame Number.
   unsigned   pid:2
 Transmited ISO Data PID.
   unsigned   ioc:1
 Interrupt On Complete.
   unsigned   sp:1
 Short Packet.
   unsigned   l:1
 Last.
   unsigned   txsts:2
 Transmit Status.
   unsigned   bs:2
 Buffer Status.
b_iso_in
 iso in quadlet bits
+


Detailed Description

+This union represents the bit fields in the DMA Descriptor status quadlet. +

+Read the quadlet into the d32 member then set/clear the bits using the bit, b_iso_out and b_iso_in elements. +

+ +

+Definition at line 1466 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniondevice__grxsts__data.html b/drivers/usb/host/dwc_otg/doc/html/uniondevice__grxsts__data.html new file mode 100644 index 000000000000..14c82c90fa0c --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniondevice__grxsts__data.html @@ -0,0 +1,62 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: device_grxsts_data Union Reference + + + + + + +

device_grxsts_data Union Reference

This union represents the bit fields in the Device Receive Status Read and Pop Registers (GRXSTSR, GRXSTSP) Read the register into the d32 element then read out the bits using the bit elements. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   epnum:4
   unsigned   bcnt:11
   unsigned   dpid:2
   unsigned   pktsts:4
   unsigned   fn:4
   unsigned   reserved:7
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Device Receive Status Read and Pop Registers (GRXSTSR, GRXSTSP) Read the register into the d32 element then read out the bits using the bit elements. +

+ +

+Definition at line 601 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniondiepint__data.html b/drivers/usb/host/dwc_otg/doc/html/uniondiepint__data.html new file mode 100644 index 000000000000..d905ea08253f --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniondiepint__data.html @@ -0,0 +1,90 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: diepint_data Union Reference + + + + + + +

diepint_data Union Reference

This union represents the bit fields in the Device IN EP Interrupt Register and the Device IN EP Common Mask Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   xfercompl:1
 Transfer complete mask.
   unsigned   epdisabled:1
 Endpoint disable mask.
   unsigned   ahberr:1
 AHB Error mask.
   unsigned   timeout:1
 TimeOUT Handshake mask (non-ISOC EPs).
   unsigned   intktxfemp:1
 IN Token received with TxF Empty mask.
   unsigned   intknepmis:1
 IN Token Received with EP mismatch mask.
   unsigned   inepnakeff:1
 IN Endpoint HAK Effective mask.
   unsigned   emptyintr:1
 IN Endpoint HAK Effective mask.
   unsigned   txfifoundrn:1
   unsigned   bna:1
 BNA Interrupt mask.
   unsigned   reserved10_12:3
   unsigned   nak:1
 BNA Interrupt mask.
   unsigned   reserved14_31:18
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Device IN EP Interrupt Register and the Device IN EP Common Mask Register. +

+

    +
  • Read the register into the d32 member then set/clear the bits using the bit elements.
+ +

+ +

+Definition at line 1030 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniondoepint__data.html b/drivers/usb/host/dwc_otg/doc/html/uniondoepint__data.html new file mode 100644 index 000000000000..cfa88a4d89c9 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniondoepint__data.html @@ -0,0 +1,98 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: doepint_data Union Reference + + + + + + +

doepint_data Union Reference

This union represents the bit fields in the Device OUT EP Interrupt Registerand Device OUT EP Common Interrupt Mask Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   xfercompl:1
 Transfer complete.
   unsigned   epdisabled:1
 Endpoint disable.
   unsigned   ahberr:1
 AHB Error.
   unsigned   setup:1
 Setup Phase Done (contorl EPs).
   unsigned   outtknepdis:1
 OUT Token Received when Endpoint Disabled.
   unsigned   stsphsercvd:1
   unsigned   back2backsetup:1
 Back-to-Back SETUP Packets Received.
   unsigned   reserved7:1
   unsigned   outpkterr:1
 OUT packet Error.
   unsigned   bna:1
 BNA Interrupt.
   unsigned   reserved10:1
   unsigned   pktdrpsts:1
 Packet Drop Status.
   unsigned   babble:1
 Babble Interrupt.
   unsigned   nak:1
 NAK Interrupt.
   unsigned   nyet:1
 NYET Interrupt.
   unsigned   reserved15_31:17
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Device OUT EP Interrupt Registerand Device OUT EP Common Interrupt Mask Register. +

+

    +
  • Read the register into the d32 member then set/clear the bits using the bit elements.
+ +

+ +

+Definition at line 1078 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniondsts__data.html b/drivers/usb/host/dwc_otg/doc/html/uniondsts__data.html new file mode 100644 index 000000000000..f2ac7549c180 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniondsts__data.html @@ -0,0 +1,68 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dsts_data Union Reference + + + + + + +

dsts_data Union Reference

This union represents the bit fields in the Device Status Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   suspsts:1
 Suspend Status.
   unsigned   enumspd:2
 Enumerated Speed.
   unsigned   errticerr:1
 Erratic Error.
   unsigned   reserved4_7:4
   unsigned   soffn:14
 Frame or Microframe Number of the received SOF.
   unsigned   reserved22_31:10
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Device Status Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. +

+ +

+Definition at line 1001 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniondthrctl__data.html b/drivers/usb/host/dwc_otg/doc/html/uniondthrctl__data.html new file mode 100644 index 000000000000..5c7730a715cf --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniondthrctl__data.html @@ -0,0 +1,178 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dthrctl_data Union Reference + + + + + + +

dthrctl_data Union Reference

This union represents Threshold control Register
    +
  • Read and write the register into the d32 member.
+ +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   non_iso_thr_en:1
 non ISO Tx Thr.
   unsigned   iso_thr_en:1
 ISO Tx Thr.
   unsigned   tx_thr_len:9
 Tx Thr.
   unsigned   ahb_thr_ratio:2
 AHB Threshold ratio.
   unsigned   reserved13_15:3
 Reserved.
   unsigned   rx_thr_en:1
 Rx Thr.
   unsigned   rx_thr_len:9
 Rx Thr.
   unsigned   reserved26_31:6
 Reserved.
b
 register bits
+


Detailed Description

+This union represents Threshold control Register
    +
  • Read and write the register into the d32 member.
+ +

+

    +
  • READ-WRITABLE Register
+ +

+ +

+Definition at line 1205 of file dwc_otg_regs.h.


Field Documentation

+ +
+
+ + + + +
unsigned dthrctl_data::non_iso_thr_en
+
+
+ +

+non ISO Tx Thr. +

+Enable +

+Definition at line 1211 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
unsigned dthrctl_data::iso_thr_en
+
+
+ +

+ISO Tx Thr. +

+Enable +

+Definition at line 1213 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
unsigned dthrctl_data::tx_thr_len
+
+
+ +

+Tx Thr. +

+Length +

+Definition at line 1215 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
unsigned dthrctl_data::rx_thr_en
+
+
+ +

+Rx Thr. +

+Enable +

+Definition at line 1221 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
unsigned dthrctl_data::rx_thr_len
+
+
+ +

+Rx Thr. +

+Length +

+Definition at line 1223 of file dwc_otg_regs.h. +

+

+


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniondtknq1__data.html b/drivers/usb/host/dwc_otg/doc/html/uniondtknq1__data.html new file mode 100644 index 000000000000..781f04f516e9 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniondtknq1__data.html @@ -0,0 +1,86 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dtknq1_data Union Reference + + + + + + +

dtknq1_data Union Reference

This union represents the bit fields in the Device IN Token Queue Read Registers. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   intknwptr:5
 In Token Queue Write Pointer.
   unsigned   reserved05_06:2
 Reserved.
   unsigned   wrap_bit:1
 write pointer has wrapped.
   unsigned   epnums0_5:24
 EP Numbers of IN Tokens 0 .
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Device IN Token Queue Read Registers. +

+

    +
  • Read the register into the d32 member.
  • READ-ONLY Register
+ +

+ +

+Definition at line 1184 of file dwc_otg_regs.h.


Field Documentation

+ +
+
+ + + + +
unsigned dtknq1_data::epnums0_5
+
+
+ +

+EP Numbers of IN Tokens 0 . +

+.. 4 +

+Definition at line 1196 of file dwc_otg_regs.h. +

+

+


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniondtxfsts__data.html b/drivers/usb/host/dwc_otg/doc/html/uniondtxfsts__data.html new file mode 100644 index 000000000000..28f2157bf056 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniondtxfsts__data.html @@ -0,0 +1,56 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dtxfsts_data Union Reference + + + + + + +

dtxfsts_data Union Reference

This union represents the bit fields in the Transmit FIFO Status Register (DTXFSTS). +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   txfspcavail:16
   unsigned   reserved:16
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Transmit FIFO Status Register (DTXFSTS). +

+Read the register into the d32 element then read out the bits using the bit elements. +

+ +

+Definition at line 697 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniondwc__otg__hcd_1_1dwc__otg__hcd__internal__flags.html b/drivers/usb/host/dwc_otg/doc/html/uniondwc__otg__hcd_1_1dwc__otg__hcd__internal__flags.html new file mode 100644 index 000000000000..b04986e7aae1 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniondwc__otg__hcd_1_1dwc__otg__hcd__internal__flags.html @@ -0,0 +1,66 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: dwc_otg_hcd::dwc_otg_hcd_internal_flags Union Reference + + + + + + + +

dwc_otg_hcd::dwc_otg_hcd_internal_flags Union Reference

Internal DWC HCD Flags. +More... +

+#include <dwc_otg_hcd.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
+struct {
   unsigned   port_connect_status_change:1
   unsigned   port_connect_status:1
   unsigned   port_reset_change:1
   unsigned   port_enable_change:1
   unsigned   port_suspend_change:1
   unsigned   port_over_current_change:1
   unsigned   port_l1_change:1
   unsigned   reserved:26
b
+


Detailed Description

+Internal DWC HCD Flags. +

+ +

+Definition at line 380 of file dwc_otg_hcd.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionfifosize__data.html b/drivers/usb/host/dwc_otg/doc/html/unionfifosize__data.html new file mode 100644 index 000000000000..ea7c6bb1ed81 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionfifosize__data.html @@ -0,0 +1,56 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: fifosize_data Union Reference + + + + + + +

fifosize_data Union Reference

This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ, GNPTXFSIZ, DPTXFSIZn, DIEPTXFn). +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   startaddr:16
   unsigned   depth:16
b
 register bits
+


Detailed Description

+This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ, GNPTXFSIZ, DPTXFSIZn, DIEPTXFn). +

+Read the register into the d32 element then read out the bits using the bit elements. +

+ +

+Definition at line 651 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniongahbcfg__data.html b/drivers/usb/host/dwc_otg/doc/html/uniongahbcfg__data.html new file mode 100644 index 000000000000..2582c0c5c9c0 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniongahbcfg__data.html @@ -0,0 +1,66 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: gahbcfg_data Union Reference + + + + + + +

gahbcfg_data Union Reference

This union represents the bit fields of the Core AHB Configuration Register (GAHBCFG). +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   glblintrmsk:1
   unsigned   hburstlen:4
   unsigned   dmaenable:1
   unsigned   reserved:1
   unsigned   nptxfemplvl_txfemplvl:1
   unsigned   ptxfemplvl:1
   unsigned   reserved9_31:23
b
 register bits
+


Detailed Description

+This union represents the bit fields of the Core AHB Configuration Register (GAHBCFG). +

+Set/clear the bits using the bit fields then write the d32 value to the register. +

+ +

+Definition at line 216 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniongi2cctl__data.html b/drivers/usb/host/dwc_otg/doc/html/uniongi2cctl__data.html new file mode 100644 index 000000000000..6a4150c84d2b --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniongi2cctl__data.html @@ -0,0 +1,72 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: gi2cctl_data Union Reference + + + + + + +

gi2cctl_data Union Reference

This union represents the bit fields in the I2C Control Register (I2CCTL). +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   rwdata:8
   unsigned   regaddr:8
   unsigned   addr:7
   unsigned   i2cen:1
   unsigned   ack:1
   unsigned   i2csuspctl:1
   unsigned   i2cdevaddr:2
   unsigned   reserved:2
   unsigned   rw:1
   unsigned   bsydne:1
b
 register bits
+


Detailed Description

+This union represents the bit fields in the I2C Control Register (I2CCTL). +

+Read the register into the d32 element then read out the bits using the bit elements. +

+ +

+Definition at line 712 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniongintmsk__data.html b/drivers/usb/host/dwc_otg/doc/html/uniongintmsk__data.html new file mode 100644 index 000000000000..fbabbb9d3538 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniongintmsk__data.html @@ -0,0 +1,114 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: gintmsk_data Union Reference + + + + + + +

gintmsk_data Union Reference

This union represents the bit fields of the Core Interrupt Mask Register (GINTMSK). +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   reserved0:1
   unsigned   modemismatch:1
   unsigned   otgintr:1
   unsigned   sofintr:1
   unsigned   rxstsqlvl:1
   unsigned   nptxfempty:1
   unsigned   ginnakeff:1
   unsigned   goutnakeff:1
   unsigned   reserved8:1
   unsigned   i2cintr:1
   unsigned   erlysuspend:1
   unsigned   usbsuspend:1
   unsigned   usbreset:1
   unsigned   enumdone:1
   unsigned   isooutdrop:1
   unsigned   eopframe:1
   unsigned   reserved16:1
   unsigned   epmismatch:1
   unsigned   inepintr:1
   unsigned   outepintr:1
   unsigned   incomplisoin:1
   unsigned   incomplisoout:1
   unsigned   reserved22_23:2
   unsigned   portintr:1
   unsigned   hcintr:1
   unsigned   ptxfempty:1
   unsigned   lpmtranrcvd:1
   unsigned   conidstschng:1
   unsigned   disconnect:1
   unsigned   sessreqintr:1
   unsigned   wkupintr:1
b
 register bits
+


Detailed Description

+This union represents the bit fields of the Core Interrupt Mask Register (GINTMSK). +

+Set/clear the bits using the bit fields then write the d32 value to the register. +

+ +

+Definition at line 512 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniongintsts__data.html b/drivers/usb/host/dwc_otg/doc/html/uniongintsts__data.html new file mode 100644 index 000000000000..059b029df50e --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniongintsts__data.html @@ -0,0 +1,114 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: gintsts_data Union Reference + + + + + + +

gintsts_data Union Reference

This union represents the bit fields of the Core Interrupt Register (GINTSTS). +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   curmode:1
   unsigned   modemismatch:1
   unsigned   otgintr:1
   unsigned   sofintr:1
   unsigned   rxstsqlvl:1
   unsigned   nptxfempty:1
   unsigned   ginnakeff:1
   unsigned   goutnakeff:1
   unsigned   reserved8:1
   unsigned   i2cintr:1
   unsigned   erlysuspend:1
   unsigned   usbsuspend:1
   unsigned   usbreset:1
   unsigned   enumdone:1
   unsigned   isooutdrop:1
   unsigned   eopframe:1
   unsigned   intokenrx:1
   unsigned   epmismatch:1
   unsigned   inepint:1
   unsigned   outepintr:1
   unsigned   incomplisoin:1
   unsigned   incomplisoout:1
   unsigned   reserved22_23:2
   unsigned   portintr:1
   unsigned   hcintr:1
   unsigned   ptxfempty:1
   unsigned   lpmtranrcvd:1
   unsigned   conidstschng:1
   unsigned   disconnect:1
   unsigned   sessreqintr:1
   unsigned   wkupintr:1
b
 register bits
+


Detailed Description

+This union represents the bit fields of the Core Interrupt Register (GINTSTS). +

+Set/clear the bits using the bit fields then write the d32 value to the register. +

+ +

+Definition at line 555 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionglpmctl__data.html b/drivers/usb/host/dwc_otg/doc/html/unionglpmctl__data.html new file mode 100644 index 000000000000..4824b451caf8 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionglpmctl__data.html @@ -0,0 +1,178 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: glpmctl_data Union Reference + + + + + + +

glpmctl_data Union Reference

This union represents the bit fields of the Core LPM Configuration Register (GLPMCFG). +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   lpm_cap_en:1
 LPM-Capable (LPMCap) (Device and Host) The application uses this bit to control the DWC_otg core LPM capabilities.
   unsigned   appl_resp:1
 LPM response programmed by application (AppL1Res) (Device) Handshake response to LPM token pre-programmed by device application software.
   unsigned   hird:4
 Host Initiated Resume Duration (HIRD) (Device and Host) In Host mode this field indicates the value of HIRD to be sent in an LPM transaction.
   unsigned   rem_wkup_en:1
 RemoteWakeEnable (bRemoteWake) (Device and Host) In Host mode this bit indicates the value of remote wake up to be sent in wIndex field of LPM transaction.
   unsigned   en_utmi_sleep:1
 Enable utmi_sleep_n (EnblSlpM) (Device and Host) The application uses this bit to control the utmi_sleep_n assertion to the PHY when in L1 state.
   unsigned   hird_thres:5
 HIRD Threshold (HIRD_Thres) (Device and Host).
   unsigned   lpm_resp:2
 LPM Response (CoreL1Res) (Device and Host) In Host mode this bit contains handsake response to LPM transaction.
   unsigned   prt_sleep_sts:1
 Port Sleep Status (SlpSts) (Device and Host) This bit is set as long as a Sleep condition is present on the USB bus.
   unsigned   sleep_state_resumeok:1
 Sleep State Resume OK (L1ResumeOK) (Device and Host) Indicates that the application or host can start resume from Sleep state.
   unsigned   lpm_chan_index:4
 LPM channel Index (LPM_Chnl_Indx) (Host) The channel number on which the LPM transaction has to be applied while sending an LPM transaction to the local device.
   unsigned   retry_count:3
 LPM Retry Count (LPM_Retry_Cnt) (Host) Number host retries that would be performed if the device response was not valid response.
   unsigned   send_lpm:1
 Send LPM Transaction (SndLPM) (Host) When set by application software, an LPM transaction containing two tokens is sent.
   unsigned   retry_count_sts:3
 LPM Retry status (LPM_RetryCnt_Sts) (Host) Number of LPM Host Retries still remaining to be transmitted for the current LPM sequence.
   unsigned   reserved28_29:2
   unsigned   hsic_connect:1
 In host mode once this bit is set, the host configures to drive the HSIC Idle state on the bus.
   unsigned   inv_sel_hsic:1
 This bit overrides and functionally inverts the if_select_hsic input port signal.
b
 register bits
+


Detailed Description

+This union represents the bit fields of the Core LPM Configuration Register (GLPMCFG). +

+Set the bits using bit fields then write the d32 value to the register. +

+ +

+Definition at line 283 of file dwc_otg_regs.h.


Field Documentation

+ +
+
+ + + + +
unsigned glpmctl_data::hird
+
+
+ +

+Host Initiated Resume Duration (HIRD) (Device and Host) In Host mode this field indicates the value of HIRD to be sent in an LPM transaction. +

+In Device mode this field is updated with the Received LPM Token HIRD bmAttribute when an ACK/NYET/STALL response is sent to an LPM transaction. +

+Definition at line 306 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
unsigned glpmctl_data::rem_wkup_en
+
+
+ +

+RemoteWakeEnable (bRemoteWake) (Device and Host) In Host mode this bit indicates the value of remote wake up to be sent in wIndex field of LPM transaction. +

+In Device mode this field is updated with the Received LPM Token bRemoteWake bmAttribute when an ACK/NYET/STALL response is sent to an LPM transaction. +

+Definition at line 315 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
unsigned glpmctl_data::lpm_resp
+
+
+ +

+LPM Response (CoreL1Res) (Device and Host) In Host mode this bit contains handsake response to LPM transaction. +

+In Device mode the response of the core to LPM transaction received is reflected in these two bits.

    +
  • 0x0 : ERROR (No handshake response)
  • 0x1 : STALL
  • 0x2 : NYET
  • 0x3 : ACK
+ +

+Definition at line 334 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
unsigned glpmctl_data::hsic_connect
+
+
+ +

+In host mode once this bit is set, the host configures to drive the HSIC Idle state on the bus. +

+It then waits for the device to initiate the Connect sequence. In device mode once this bit is set, the device waits for the HSIC Idle line state on the bus. Upon receving the Idle line state, it initiates the HSIC Connect sequence. +

+Definition at line 375 of file dwc_otg_regs.h. +

+

+


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniongnptxsts__data.html b/drivers/usb/host/dwc_otg/doc/html/uniongnptxsts__data.html new file mode 100644 index 000000000000..fb3adeed2070 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniongnptxsts__data.html @@ -0,0 +1,69 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: gnptxsts_data Union Reference + + + + + + +

gnptxsts_data Union Reference

This union represents the bit fields in the Non-Periodic Transmit FIFO/Queue Status Register (GNPTXSTS). +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   nptxfspcavail:16
   unsigned   nptxqspcavail:8
   unsigned   nptxqtop_terminate:1
 Top of the Non-Periodic Transmit Request Queue
    +
  • bit 24 - Terminate (Last entry for the selected channel/EP)
  • bits 26:25 - Token Type
      +
    • 2'b00 - IN/OUT
    • 2'b01 - Zero Length OUT
    • 2'b10 - PING/Complete Split
    • 2'b11 - Channel Halt
    +
  • bits 30:27 - Channel/EP Number.
+
   unsigned   nptxqtop_token:2
   unsigned   nptxqtop_chnep:4
   unsigned   reserved:1
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Non-Periodic Transmit FIFO/Queue Status Register (GNPTXSTS). +

+Read the register into the d32 element then read out the bits using the bit elements. +

+ +

+Definition at line 667 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniongotgctl__data.html b/drivers/usb/host/dwc_otg/doc/html/uniongotgctl__data.html new file mode 100644 index 000000000000..d2d4d35497b7 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniongotgctl__data.html @@ -0,0 +1,80 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: gotgctl_data Union Reference + + + + + + +

gotgctl_data Union Reference

This union represents the bit fields of the Core OTG Control and Status Register (GOTGCTL). +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   sesreqscs:1
   unsigned   sesreq:1
   unsigned   reserved2_7:6
   unsigned   hstnegscs:1
   unsigned   hnpreq:1
   unsigned   hstsethnpen:1
   unsigned   devhnpen:1
   unsigned   reserved12_15:4
   unsigned   conidsts:1
   unsigned   reserved17:1
   unsigned   asesvld:1
   unsigned   bsesvld:1
   unsigned   currmod:1
   unsigned   reserved21_31:11
b
 register bits
+


Detailed Description

+This union represents the bit fields of the Core OTG Control and Status Register (GOTGCTL). +

+Set the bits using the bit fields then write the d32 value to the register. +

+ +

+Definition at line 152 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniongotgint__data.html b/drivers/usb/host/dwc_otg/doc/html/uniongotgint__data.html new file mode 100644 index 000000000000..d79e3e1b087c --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniongotgint__data.html @@ -0,0 +1,79 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: gotgint_data Union Reference + + + + + + +

gotgint_data Union Reference

This union represents the bit fields of the Core OTG Interrupt Register (GOTGINT). +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   reserved0_1:2
 Current Mode.
   unsigned   sesenddet:1
 Session End Detected.
   unsigned   reserved3_7:5
   unsigned   sesreqsucstschng:1
 Session Request Success Status Change.
   unsigned   hstnegsucstschng:1
 Host Negotiation Success Status Change.
   unsigned   reserver10_16:7
   unsigned   hstnegdet:1
 Host Negotiation Detected.
   unsigned   adevtoutchng:1
 A-Device Timeout Change.
   unsigned   debdone:1
 Debounce Done.
   unsigned   reserved31_20:12
b
 register bits
+


Detailed Description

+This union represents the bit fields of the Core OTG Interrupt Register (GOTGINT). +

+Set/clear the bits using the bit fields then write the d32 value to the register. +

+ +

+Definition at line 179 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniongrstctl__data.html b/drivers/usb/host/dwc_otg/doc/html/uniongrstctl__data.html new file mode 100644 index 000000000000..b5df93cfc76f --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniongrstctl__data.html @@ -0,0 +1,249 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: grstctl_data Union Reference + + + + + + +

grstctl_data Union Reference

This union represents the bit fields of the Core Reset Register (GRSTCTL). +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   csftrst:1
 Core Soft Reset (CSftRst) (Device and Host).
   unsigned   hsftrst:1
 Hclk Soft Reset.
   unsigned   hstfrm:1
 Host Frame Counter Reset (Host Only)
+.
   unsigned   intknqflsh:1
 In Token Sequence Learning Queue Flush (INTknQFlsh) (Device Only).
   unsigned   rxfflsh:1
 RxFIFO Flush (RxFFlsh) (Device and Host).
   unsigned   txfflsh:1
 TxFIFO Flush (TxFFlsh) (Device and Host).
   unsigned   txfnum:5
 TxFIFO Number (TxFNum) (Device and Host).
   unsigned   reserved11_29:19
 Reserved.
   unsigned   dmareq:1
 DMA Request Signal.
   unsigned   ahbidle:1
 AHB Master Idle.
b
 register bits
+


Detailed Description

+This union represents the bit fields of the Core Reset Register (GRSTCTL). +

+Set/clear the bits using the bit fields then write the d32 value to the register. +

+ +

+Definition at line 388 of file dwc_otg_regs.h.


Field Documentation

+ +
+
+ + + + +
unsigned grstctl_data::csftrst
+
+
+ +

+Core Soft Reset (CSftRst) (Device and Host). +

+The application can flush the control logic in the entire core using this bit. This bit resets the pipelines in the AHB Clock domain as well as the PHY Clock domain.

+The state machines are reset to an IDLE state, the control bits in the CSRs are cleared, all the transmit FIFOs and the receive FIFO are flushed.

+The status mask bits that control the generation of the interrupt, are cleared, to clear the interrupt. The interrupt status bits are not cleared, so the application can get the status of any events that occurred in the core after it has set this bit.

+Any transactions on the AHB are terminated as soon as possible following the protocol. Any transactions on the USB are terminated immediately.

+The configuration settings in the CSRs are unchanged, so the software doesn't have to reprogram these registers (Device Configuration/Host Configuration/Core System Configuration/Core PHY Configuration).

+The application can write to this bit, any time it wants to reset the core. This is a self clearing bit and the core clears this bit after all the necessary logic is reset in the core, which may take several clocks, depending on the current state of the core. +

+Definition at line 428 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
unsigned grstctl_data::hsftrst
+
+
+ +

+Hclk Soft Reset. +

+The application uses this bit to reset the control logic in the AHB clock domain. Only AHB clock domain pipelines are reset. +

+Definition at line 435 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
unsigned grstctl_data::hstfrm
+
+
+ +

+Host Frame Counter Reset (Host Only)
+. +

+The application can reset the (micro)frame number counter inside the core, using this bit. When the (micro)frame counter is reset, the subsequent SOF sent out by the core, will have a (micro)frame number of 0. +

+Definition at line 444 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
unsigned grstctl_data::rxfflsh
+
+
+ +

+RxFIFO Flush (RxFFlsh) (Device and Host). +

+The application can flush the entire Receive FIFO using this bit.

+The application must first ensure that the core is not in the middle of a transaction.

+The application should write into this bit, only after making sure that neither the DMA engine is reading from the RxFIFO nor the MAC is writing the data in to the FIFO.

+The application should wait until the bit is cleared before performing any other operations. This bit will takes 8 clocks (slowest of PHY or AHB clock) to clear. +

+Definition at line 463 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
unsigned grstctl_data::txfflsh
+
+
+ +

+TxFIFO Flush (TxFFlsh) (Device and Host). +

+This bit is used to selectively flush a single or all transmit FIFOs. The application must first ensure that the core is not in the middle of a transaction.

+The application should write into this bit, only after making sure that neither the DMA engine is writing into the TxFIFO nor the MAC is reading the data out of the FIFO.

+The application should wait until the core clears this bit, before performing any operations. This bit will takes 8 clocks (slowest of PHY or AHB clock) to clear. +

+Definition at line 478 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
unsigned grstctl_data::txfnum
+
+
+ +

+TxFIFO Number (TxFNum) (Device and Host). +

+This is the FIFO number which needs to be flushed, using the TxFIFO Flush bit. This field should not be changed until the TxFIFO Flush bit is cleared by the core.

    +
  • 0x0 : Non Periodic TxFIFO Flush
  • 0x1 : Periodic TxFIFO #1 Flush in device mode or Periodic TxFIFO in host mode
  • 0x2 : Periodic TxFIFO #2 Flush in device mode.
  • ...
  • 0xF : Periodic TxFIFO #15 Flush in device mode
  • 0x10: Flush all the Transmit NonPeriodic and Transmit Periodic FIFOs in the core
+ +

+Definition at line 495 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
unsigned grstctl_data::dmareq
+
+
+ +

+DMA Request Signal. +

+Indicated DMA request is in probress. Used for debug purpose. +

+Definition at line 500 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
unsigned grstctl_data::ahbidle
+
+
+ +

+AHB Master Idle. +

+Indicates the AHB Master State Machine is in IDLE condition. +

+Definition at line 503 of file dwc_otg_regs.h. +

+

+


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/uniongusbcfg__data.html b/drivers/usb/host/dwc_otg/doc/html/uniongusbcfg__data.html new file mode 100644 index 000000000000..970fe47e683d --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/uniongusbcfg__data.html @@ -0,0 +1,98 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: gusbcfg_data Union Reference + + + + + + +

gusbcfg_data Union Reference

This union represents the bit fields of the Core USB Configuration Register (GUSBCFG). +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   toutcal:3
   unsigned   phyif:1
   unsigned   ulpi_utmi_sel:1
   unsigned   fsintf:1
   unsigned   physel:1
   unsigned   ddrsel:1
   unsigned   srpcap:1
   unsigned   hnpcap:1
   unsigned   usbtrdtim:4
   unsigned   nptxfrwnden:1
   unsigned   phylpwrclksel:1
   unsigned   otgutmifssel:1
   unsigned   ulpi_fsls:1
   unsigned   ulpi_auto_res:1
   unsigned   ulpi_clk_sus_m:1
   unsigned   ulpi_ext_vbus_drv:1
   unsigned   ulpi_int_vbus_indicator:1
   unsigned   term_sel_dl_pulse:1
   unsigned   reserved23_25:3
   unsigned   ic_usb_cap:1
   unsigned   ic_traffic_pull_remove:1
   unsigned   tx_end_delay:1
   unsigned   reserved29_31:3
b
 register bits
+


Detailed Description

+This union represents the bit fields of the Core USB Configuration Register (GUSBCFG). +

+Set the bits using the bit fields then write the d32 value to the register. +

+ +

+Definition at line 247 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionhaint__data.html b/drivers/usb/host/dwc_otg/doc/html/unionhaint__data.html new file mode 100644 index 000000000000..55773ff0b89a --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionhaint__data.html @@ -0,0 +1,93 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: haint_data Union Reference + + + + + + +

haint_data Union Reference

This union represents the bit fields in the Host All Interrupt Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   ch0:1
   unsigned   ch1:1
   unsigned   ch2:1
   unsigned   ch3:1
   unsigned   ch4:1
   unsigned   ch5:1
   unsigned   ch6:1
   unsigned   ch7:1
   unsigned   ch8:1
   unsigned   ch9:1
   unsigned   ch10:1
   unsigned   ch11:1
   unsigned   ch12:1
   unsigned   ch13:1
   unsigned   ch14:1
   unsigned   ch15:1
   unsigned   reserved:16
b
 register bits
+struct {
   unsigned   chint:16
   unsigned   reserved:16
b2
+


Detailed Description

+This union represents the bit fields in the Host All Interrupt Register. +

+ +

+Definition at line 1771 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionhaintmsk__data.html b/drivers/usb/host/dwc_otg/doc/html/unionhaintmsk__data.html new file mode 100644 index 000000000000..175595875429 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionhaintmsk__data.html @@ -0,0 +1,93 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: haintmsk_data Union Reference + + + + + + +

haintmsk_data Union Reference

This union represents the bit fields in the Host All Interrupt Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   ch0:1
   unsigned   ch1:1
   unsigned   ch2:1
   unsigned   ch3:1
   unsigned   ch4:1
   unsigned   ch5:1
   unsigned   ch6:1
   unsigned   ch7:1
   unsigned   ch8:1
   unsigned   ch9:1
   unsigned   ch10:1
   unsigned   ch11:1
   unsigned   ch12:1
   unsigned   ch13:1
   unsigned   ch14:1
   unsigned   ch15:1
   unsigned   reserved:16
b
 register bits
+struct {
   unsigned   chint:16
   unsigned   reserved:16
b2
+


Detailed Description

+This union represents the bit fields in the Host All Interrupt Register. +

+ +

+Definition at line 1805 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionhcchar__data.html b/drivers/usb/host/dwc_otg/doc/html/unionhcchar__data.html new file mode 100644 index 000000000000..14a5823f3b5f --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionhcchar__data.html @@ -0,0 +1,123 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: hcchar_data Union Reference + + + + + + +

hcchar_data Union Reference

This union represents the bit fields in the Host Channel Characteristics Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   mps:11
 Maximum packet size in bytes.
   unsigned   epnum:4
 Endpoint number.
   unsigned   epdir:1
 0: OUT, 1: IN
   unsigned   reserved:1
   unsigned   lspddev:1
 0: Full/high speed device, 1: Low speed device
   unsigned   eptype:2
 0: Control, 1: Isoc, 2: Bulk, 3: Intr
   unsigned   multicnt:2
 Packets per frame for periodic transfers.
   unsigned   devaddr:7
 Device address.
   unsigned   oddfrm:1
 Frame to transmit periodic transaction.
   unsigned   chdis:1
 Channel disable.
   unsigned   chen:1
 Channel enable.
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Host Channel Characteristics Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. Write the d32 member to the hcchar register. +

+ +

+Definition at line 1863 of file dwc_otg_regs.h.


Field Documentation

+ +
+
+ + + + +
unsigned hcchar_data::multicnt
+
+
+ +

+Packets per frame for periodic transfers. +

+0 is reserved. +

+Definition at line 1887 of file dwc_otg_regs.h. +

+

+ +

+
+ + + + +
unsigned hcchar_data::oddfrm
+
+
+ +

+Frame to transmit periodic transaction. +

+0: even, 1: odd +

+Definition at line 1896 of file dwc_otg_regs.h. +

+

+


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionhcdma__data.html b/drivers/usb/host/dwc_otg/doc/html/unionhcdma__data.html new file mode 100644 index 000000000000..4508ac2f7645 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionhcdma__data.html @@ -0,0 +1,78 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: hcdma_data Union Reference + + + + + + +

hcdma_data Union Reference

This union represents the bit fields in the Host DMA Address Register used in Descriptor DMA mode. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   reserved0_2: 3
   unsigned   ctd: 8
 Current Transfer Descriptor.
   unsigned   dma_addr: 21
 Start Address of Descriptor List.
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Host DMA Address Register used in Descriptor DMA mode. +

+ +

+Definition at line 2086 of file dwc_otg_regs.h.


Field Documentation

+ +
+
+ + + + +
unsigned hcdma_data::ctd
+
+
+ +

+Current Transfer Descriptor. +

+Not used for ISOC +

+Definition at line 2095 of file dwc_otg_regs.h. +

+

+


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionhcfg__data.html b/drivers/usb/host/dwc_otg/doc/html/unionhcfg__data.html new file mode 100644 index 000000000000..56846ebf514a --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionhcfg__data.html @@ -0,0 +1,72 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: hcfg_data Union Reference + + + + + + +

hcfg_data Union Reference

This union represents the bit fields in the Host Configuration Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   fslspclksel:2
 FS/LS Phy Clock Select.
   unsigned   fslssupp:1
 FS/LS Only Support.
   unsigned   reserved3_22: 20
   unsigned   descdma: 1
 Enable Scatter/gather DMA in Host mode.
   unsigned   frlisten: 2
 Frame List Entries.
   unsigned   perschedena: 1
 Enable Periodic Scheduling.
   unsigned   perschedstat: 1
 Periodic Scheduling Enabled Status.
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Host Configuration Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. Write the d32 member to the hcfg register. +

+ +

+Definition at line 1652 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionhcint__data.html b/drivers/usb/host/dwc_otg/doc/html/unionhcint__data.html new file mode 100644 index 000000000000..0bdb8de26d33 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionhcint__data.html @@ -0,0 +1,95 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: hcint_data Union Reference + + + + + + +

hcint_data Union Reference

This union represents the bit fields in the Host All Interrupt Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   xfercomp:1
 Transfer Complete.
   unsigned   chhltd:1
 Channel Halted.
   unsigned   ahberr:1
 AHB Error.
   unsigned   stall:1
 STALL Response Received.
   unsigned   nak:1
 NAK Response Received.
   unsigned   ack:1
 ACK Response Received.
   unsigned   nyet:1
 NYET Response Received.
   unsigned   xacterr:1
 Transaction Err.
   unsigned   bblerr:1
 Babble Error.
   unsigned   frmovrun:1
 Frame Overrun.
   unsigned   datatglerr:1
 Data Toggle Error.
   unsigned   bna: 1
 Buffer Not Available (only for DDMA mode).
   unsigned   xcs_xact: 1
 Exessive transaction error (only for DDMA mode).
   unsigned   frm_list_roll: 1
 Frame List Rollover interrupt.
   unsigned   reserved14_31: 18
 Reserved.
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Host All Interrupt Register. +

+ +

+Definition at line 1940 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionhcintmsk__data.html b/drivers/usb/host/dwc_otg/doc/html/unionhcintmsk__data.html new file mode 100644 index 000000000000..06321b1e288b --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionhcintmsk__data.html @@ -0,0 +1,82 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: hcintmsk_data Union Reference + + + + + + +

hcintmsk_data Union Reference

This union represents the bit fields in the Host Channel Interrupt Mask Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   xfercompl: 1
   unsigned   chhltd: 1
   unsigned   ahberr: 1
   unsigned   stall: 1
   unsigned   nak: 1
   unsigned   ack: 1
   unsigned   nyet: 1
   unsigned   xacterr: 1
   unsigned   bblerr: 1
   unsigned   frmovrun: 1
   unsigned   datatglerr: 1
   unsigned   bna: 1
   unsigned   xcs_xact: 1
   unsigned   frm_list_roll: 1
   unsigned   reserved14_31: 18
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Host Channel Interrupt Mask Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. Write the d32 member to the hcintmsk register. +

+ +

+Definition at line 1986 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionhcsplt__data.html b/drivers/usb/host/dwc_otg/doc/html/unionhcsplt__data.html new file mode 100644 index 000000000000..713a5b584f18 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionhcsplt__data.html @@ -0,0 +1,63 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: hcsplt_data Union Reference + + + + + + +

hcsplt_data Union Reference

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   prtaddr:7
 Port Address.
   unsigned   hubaddr:7
 Hub Address.
   unsigned   xactpos:2
 Transaction Position.
   unsigned   compsplt:1
 Do Complete Split.
   unsigned   reserved:14
 Reserved.
   unsigned   spltena:1
 Split Enble.
b
 register bits
+

Detailed Description

+ +

+ +

+Definition at line 1906 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionhctsiz__data.html b/drivers/usb/host/dwc_otg/doc/html/unionhctsiz__data.html new file mode 100644 index 000000000000..36928a1ba356 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionhctsiz__data.html @@ -0,0 +1,105 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: hctsiz_data Union Reference + + + + + + +

hctsiz_data Union Reference

This union represents the bit fields in the Host Channel Transfer Size Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   xfersize:19
 Total transfer size in bytes.
   unsigned   pktcnt:10
 Data packets to transfer.
   unsigned   pid:2
 Packet ID for next data packet 0: DATA0 1: DATA2 2: DATA1 3: MDATA (non-Control), SETUP (Control).
   unsigned   dopng:1
 Do PING protocol when 1.
b
 register bits
+struct {
   unsigned   schinfo: 8
 Scheduling information.
   unsigned   ntd: 8
 Number of transfer descriptors.
   unsigned   reserved16_28: 13
 Data packets to transfer.
   unsigned   pid: 2
 Packet ID for next data packet 0: DATA0 1: DATA2 2: DATA1 3: MDATA (non-Control).
   unsigned   dopng: 1
 Do PING protocol when 1.
b_ddma
 register bits
+


Detailed Description

+This union represents the bit fields in the Host Channel Transfer Size Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. Write the d32 member to the hcchar register. +

+ +

+Definition at line 2019 of file dwc_otg_regs.h.


Field Documentation

+ +
+
+ + + + +
unsigned hctsiz_data::ntd
+
+
+ +

+Number of transfer descriptors. +

+Max value: 64 in general, 256 only for HS isochronous endpoint. +

+Definition at line 2062 of file dwc_otg_regs.h. +

+

+


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionhfir__data.html b/drivers/usb/host/dwc_otg/doc/html/unionhfir__data.html new file mode 100644 index 000000000000..a29b19fd29f9 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionhfir__data.html @@ -0,0 +1,54 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: hfir_data Union Reference + + + + + + +

hfir_data Union Reference

This union represents the bit fields in the Host Frame Remaing/Number Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   frint:16
   unsigned   reserved:16
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Host Frame Remaing/Number Register. +

+ +

+Definition at line 1684 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionhfnum__data.html b/drivers/usb/host/dwc_otg/doc/html/unionhfnum__data.html new file mode 100644 index 000000000000..0dbdb8917935 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionhfnum__data.html @@ -0,0 +1,54 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: hfnum_data Union Reference + + + + + + +

hfnum_data Union Reference

This union represents the bit fields in the Host Frame Remaing/Number Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   frnum:16
   unsigned   frrem:16
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Host Frame Remaing/Number Register. +

+ +

+Definition at line 1699 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionhost__dma__desc__sts.html b/drivers/usb/host/dwc_otg/doc/html/unionhost__dma__desc__sts.html new file mode 100644 index 000000000000..487cb1ce9839 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionhost__dma__desc__sts.html @@ -0,0 +1,123 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: host_dma_desc_sts Union Reference + + + + + + +

host_dma_desc_sts Union Reference

This union represents the bit fields in the DMA Descriptor status quadlet for host mode. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   n_bytes: 17
 Number of bytes.
   unsigned   qtd_offset: 6
 QTD offset to jump when Short Packet received - only for IN EPs.
   unsigned   a_qtd: 1
 Set to request the core to jump to alternate QTD if Short Packet received - only for IN EPs.
   unsigned   sup: 1
 Setup Packet bit.
   unsigned   ioc: 1
 Interrupt On Complete.
   unsigned   eol: 1
 End of List.
   unsigned   reserved27: 1
   unsigned   sts: 2
 Rx/Tx Status.
   unsigned   reserved30: 1
   unsigned   a: 1
 Active Bit.
b
 quadlet bits
+struct {
   unsigned   n_bytes: 12
 Number of bytes.
   unsigned   reserved12_24: 13
   unsigned   ioc: 1
 Interrupt On Complete.
   unsigned   reserved26_27: 2
   unsigned   sts: 2
 Rx/Tx Status.
   unsigned   reserved30: 1
   unsigned   a: 1
 Active Bit.
b_isoc
+


Detailed Description

+This union represents the bit fields in the DMA Descriptor status quadlet for host mode. +

+Read the quadlet into the d32 member then set/clear the bits using the bit elements. +

+ +

+Definition at line 2106 of file dwc_otg_regs.h.


Field Documentation

+ +
+
+ + + + +
unsigned host_dma_desc_sts::sup
+
+
+ +

+Setup Packet bit. +

+When set indicates that buffer contains setup packet. +

+Definition at line 2127 of file dwc_otg_regs.h. +

+

+


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionhost__grxsts__data.html b/drivers/usb/host/dwc_otg/doc/html/unionhost__grxsts__data.html new file mode 100644 index 000000000000..12927484d523 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionhost__grxsts__data.html @@ -0,0 +1,60 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: host_grxsts_data Union Reference + + + + + + +

host_grxsts_data Union Reference

This union represents the bit fields in the Host Receive Status Read and Pop Registers (GRXSTSR, GRXSTSP) Read the register into the d32 element then read out the bits using the bit elements. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   chnum:4
   unsigned   bcnt:11
   unsigned   dpid:2
   unsigned   pktsts:4
   unsigned   reserved:11
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Host Receive Status Read and Pop Registers (GRXSTSR, GRXSTSP) Read the register into the d32 element then read out the bits using the bit elements. +

+ +

+Definition at line 627 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionhprt0__data.html b/drivers/usb/host/dwc_otg/doc/html/unionhprt0__data.html new file mode 100644 index 000000000000..084592c880cd --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionhprt0__data.html @@ -0,0 +1,82 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: hprt0_data Union Reference + + + + + + +

hprt0_data Union Reference

This union represents the bit fields in the Host Port Control and Status Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   prtconnsts:1
   unsigned   prtconndet:1
   unsigned   prtena:1
   unsigned   prtenchng:1
   unsigned   prtovrcurract:1
   unsigned   prtovrcurrchng:1
   unsigned   prtres:1
   unsigned   prtsusp:1
   unsigned   prtrst:1
   unsigned   reserved9:1
   unsigned   prtlnsts:2
   unsigned   prtpwr:1
   unsigned   prttstctl:4
   unsigned   prtspd:2
   unsigned   reserved19_31:13
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Host Port Control and Status Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. Write the d32 member to the hprt0 register. +

+ +

+Definition at line 1741 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionhptxsts__data.html b/drivers/usb/host/dwc_otg/doc/html/unionhptxsts__data.html new file mode 100644 index 000000000000..584cb23cbde3 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionhptxsts__data.html @@ -0,0 +1,62 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: hptxsts_data Union Reference + + + + + + +

hptxsts_data Union Reference

+ + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   ptxfspcavail:16
   unsigned   ptxqspcavail:8
   unsigned   ptxqtop_terminate:1
 Top of the Periodic Transmit Request Queue
    +
  • bit 24 - Terminate (last entry for the selected channel)
  • bits 26:25 - Token Type
      +
    • 2'b00 - Zero length
    • 2'b01 - Ping
    • 2'b10 - Disable
    +
  • bits 30:27 - Channel Number
  • bit 31 - Odd/even microframe.
+
   unsigned   ptxqtop_token:2
   unsigned   ptxqtop_chnum:4
   unsigned   ptxqtop_odd:1
b
 register bits
+

Detailed Description

+ +

+ +

+Definition at line 1711 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionhwcfg1__data.html b/drivers/usb/host/dwc_otg/doc/html/unionhwcfg1__data.html new file mode 100644 index 000000000000..33ce67eb32fa --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionhwcfg1__data.html @@ -0,0 +1,84 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: hwcfg1_data Union Reference + + + + + + +

hwcfg1_data Union Reference

This union represents the bit fields in the User HW Config1 Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   ep_dir0:2
   unsigned   ep_dir1:2
   unsigned   ep_dir2:2
   unsigned   ep_dir3:2
   unsigned   ep_dir4:2
   unsigned   ep_dir5:2
   unsigned   ep_dir6:2
   unsigned   ep_dir7:2
   unsigned   ep_dir8:2
   unsigned   ep_dir9:2
   unsigned   ep_dir10:2
   unsigned   ep_dir11:2
   unsigned   ep_dir12:2
   unsigned   ep_dir13:2
   unsigned   ep_dir14:2
   unsigned   ep_dir15:2
b
 register bits
+


Detailed Description

+This union represents the bit fields in the User HW Config1 Register. +

+Read the register into the d32 element then read out the bits using the bit elements. +

+ +

+Definition at line 735 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionhwcfg2__data.html b/drivers/usb/host/dwc_otg/doc/html/unionhwcfg2__data.html new file mode 100644 index 000000000000..4053c1238783 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionhwcfg2__data.html @@ -0,0 +1,82 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: hwcfg2_data Union Reference + + + + + + +

hwcfg2_data Union Reference

This union represents the bit fields in the User HW Config2 Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   op_mode:3
   unsigned   architecture:2
   unsigned   point2point:1
   unsigned   hs_phy_type:2
   unsigned   fs_phy_type:2
   unsigned   num_dev_ep:4
   unsigned   num_host_chan:4
   unsigned   perio_ep_supported:1
   unsigned   dynamic_fifo:1
   unsigned   multi_proc_int:1
   unsigned   reserved21:1
   unsigned   nonperio_tx_q_depth:2
   unsigned   host_perio_tx_q_depth:2
   unsigned   dev_token_q_depth:5
   unsigned   reserved31:1
b
 register bits
+


Detailed Description

+This union represents the bit fields in the User HW Config2 Register. +

+Read the register into the d32 element then read out the bits using the bit elements. +

+ +

+Definition at line 764 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionhwcfg3__data.html b/drivers/usb/host/dwc_otg/doc/html/unionhwcfg3__data.html new file mode 100644 index 000000000000..cdde7e2d6305 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionhwcfg3__data.html @@ -0,0 +1,76 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: hwcfg3_data Union Reference + + + + + + +

hwcfg3_data Union Reference

This union represents the bit fields in the User HW Config3 Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   xfer_size_cntr_width:4
   unsigned   packet_size_cntr_width:3
   unsigned   otg_func:1
   unsigned   i2c:1
   unsigned   vendor_ctrl_if:1
   unsigned   optional_features:1
   unsigned   synch_reset_type:1
   unsigned   otg_enable_ic_usb:1
   unsigned   otg_enable_hsic:1
   unsigned   reserved14:1
   unsigned   otg_lpm_en:1
   unsigned   dfifo_depth:16
b
 register bits
+


Detailed Description

+This union represents the bit fields in the User HW Config3 Register. +

+Read the register into the d32 element then read out the bits using the bit elements. +

+ +

+Definition at line 806 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionhwcfg4__data.html b/drivers/usb/host/dwc_otg/doc/html/unionhwcfg4__data.html new file mode 100644 index 000000000000..a0e27f721cda --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionhwcfg4__data.html @@ -0,0 +1,80 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: hwcfg4_data Union Reference + + + + + + +

hwcfg4_data Union Reference

This union represents the bit fields in the User HW Config4 Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   num_dev_perio_in_ep:4
   unsigned   power_optimiz:1
   unsigned   min_ahb_freq:9
   unsigned   utmi_phy_data_width:2
   unsigned   num_dev_mode_ctrl_ep:4
   unsigned   iddig_filt_en:1
   unsigned   vbus_valid_filt_en:1
   unsigned   a_valid_filt_en:1
   unsigned   b_valid_filt_en:1
   unsigned   session_end_filt_en:1
   unsigned   ded_fifo_en:1
   unsigned   num_in_eps:4
   unsigned   desc_dma:1
   unsigned   desc_dma_dyn:1
b
 register bits
+


Detailed Description

+This union represents the bit fields in the User HW Config4 Register. +

+Read the register into the d32 element then read out the bits using the bit elements. +

+ +

+Definition at line 832 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/doc/html/unionpcgcctl__data.html b/drivers/usb/host/dwc_otg/doc/html/unionpcgcctl__data.html new file mode 100644 index 000000000000..dc9d6583ede8 --- /dev/null +++ b/drivers/usb/host/dwc_otg/doc/html/unionpcgcctl__data.html @@ -0,0 +1,78 @@ + + +DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver: pcgcctl_data Union Reference + + + + + + +

pcgcctl_data Union Reference

This union represents the bit fields in the Power and Clock Gating Control Register. +More... +

+#include <dwc_otg_regs.h> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Fields

+uint32_t d32
 raw register data
+struct {
   unsigned   stoppclk:1
 Stop Pclk.
   unsigned   gatehclk:1
 Gate Hclk.
   unsigned   pwrclmp:1
 Power Clamp.
   unsigned   rstpdwnmodule:1
 Reset Power Down Modules.
   unsigned   physuspended:1
 PHY Suspended.
   unsigned   enbl_sleep_gating:1
 Enable Sleep Clock Gating (Enbl_L1Gating).
   unsigned   phy_in_sleep:1
 PHY In Sleep (PhySleep).
   unsigned   deep_sleep:1
 Deep Sleep.
   unsigned   reserved31_8:24
b
 register bits
+


Detailed Description

+This union represents the bit fields in the Power and Clock Gating Control Register. +

+Read the register into the d32 member then set/clear the bits using the bit elements. +

+ +

+Definition at line 2210 of file dwc_otg_regs.h.


The documentation for this union was generated from the following file: +
Generated on Tue May 5 02:22:49 2009 for DesignWare USB 2.0 OTG Controller (DWC_otg) Device Driver by  + +doxygen 1.4.7
+ + diff --git a/drivers/usb/host/dwc_otg/dummy_audio.c b/drivers/usb/host/dwc_otg/dummy_audio.c new file mode 100644 index 000000000000..530ac8bafb82 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dummy_audio.c @@ -0,0 +1,1575 @@ +/* + * zero.c -- Gadget Zero, for USB development + * + * Copyright (C) 2003-2004 David Brownell + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/* + * Gadget Zero only needs two bulk endpoints, and is an example of how you + * can write a hardware-agnostic gadget driver running inside a USB device. + * + * Hardware details are visible (see CONFIG_USB_ZERO_* below) but don't + * affect most of the driver. + * + * Use it with the Linux host/master side "usbtest" driver to get a basic + * functional test of your device-side usb stack, or with "usb-skeleton". + * + * It supports two similar configurations. One sinks whatever the usb host + * writes, and in return sources zeroes. The other loops whatever the host + * writes back, so the host can read it. Module options include: + * + * buflen=N default N=4096, buffer size used + * qlen=N default N=32, how many buffers in the loopback queue + * loopdefault default false, list loopback config first + * + * Many drivers will only have one configuration, letting them be much + * simpler if they also don't support high speed operation (like this + * driver does). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21) +# include +#else +# include +#endif + +#include + + +/*-------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------*/ + + +static int utf8_to_utf16le(const char *s, u16 *cp, unsigned len) +{ + int count = 0; + u8 c; + u16 uchar; + + /* this insists on correct encodings, though not minimal ones. + * BUT it currently rejects legit 4-byte UTF-8 code points, + * which need surrogate pairs. (Unicode 3.1 can use them.) + */ + while (len != 0 && (c = (u8) *s++) != 0) { + if (unlikely(c & 0x80)) { + // 2-byte sequence: + // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx + if ((c & 0xe0) == 0xc0) { + uchar = (c & 0x1f) << 6; + + c = (u8) *s++; + if ((c & 0xc0) != 0xc0) + goto fail; + c &= 0x3f; + uchar |= c; + + // 3-byte sequence (most CJKV characters): + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx + } else if ((c & 0xf0) == 0xe0) { + uchar = (c & 0x0f) << 12; + + c = (u8) *s++; + if ((c & 0xc0) != 0xc0) + goto fail; + c &= 0x3f; + uchar |= c << 6; + + c = (u8) *s++; + if ((c & 0xc0) != 0xc0) + goto fail; + c &= 0x3f; + uchar |= c; + + /* no bogus surrogates */ + if (0xd800 <= uchar && uchar <= 0xdfff) + goto fail; + + // 4-byte sequence (surrogate pairs, currently rare): + // 11101110wwwwzzzzyy + 110111yyyyxxxxxx + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx + // (uuuuu = wwww + 1) + // FIXME accept the surrogate code points (only) + + } else + goto fail; + } else + uchar = c; + put_unaligned (cpu_to_le16 (uchar), cp++); + count++; + len--; + } + return count; +fail: + return -1; +} + + +/** + * usb_gadget_get_string - fill out a string descriptor + * @table: of c strings encoded using UTF-8 + * @id: string id, from low byte of wValue in get string descriptor + * @buf: at least 256 bytes + * + * Finds the UTF-8 string matching the ID, and converts it into a + * string descriptor in utf16-le. + * Returns length of descriptor (always even) or negative errno + * + * If your driver needs stings in multiple languages, you'll probably + * "switch (wIndex) { ... }" in your ep0 string descriptor logic, + * using this routine after choosing which set of UTF-8 strings to use. + * Note that US-ASCII is a strict subset of UTF-8; any string bytes with + * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1 + * characters (which are also widely used in C strings). + */ +int +usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf) +{ + struct usb_string *s; + int len; + + /* descriptor 0 has the language id */ + if (id == 0) { + buf [0] = 4; + buf [1] = USB_DT_STRING; + buf [2] = (u8) table->language; + buf [3] = (u8) (table->language >> 8); + return 4; + } + for (s = table->strings; s && s->s; s++) + if (s->id == id) + break; + + /* unrecognized: stall. */ + if (!s || !s->s) + return -EINVAL; + + /* string descriptors have length, tag, then UTF16-LE text */ + len = min ((size_t) 126, strlen (s->s)); + memset (buf + 2, 0, 2 * len); /* zero all the bytes */ + len = utf8_to_utf16le(s->s, (u16 *)&buf[2], len); + if (len < 0) + return -EINVAL; + buf [0] = (len + 1) * 2; + buf [1] = USB_DT_STRING; + return buf [0]; +} + + +/*-------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------*/ + + +/** + * usb_descriptor_fillbuf - fill buffer with descriptors + * @buf: Buffer to be filled + * @buflen: Size of buf + * @src: Array of descriptor pointers, terminated by null pointer. + * + * Copies descriptors into the buffer, returning the length or a + * negative error code if they can't all be copied. Useful when + * assembling descriptors for an associated set of interfaces used + * as part of configuring a composite device; or in other cases where + * sets of descriptors need to be marshaled. + */ +int +usb_descriptor_fillbuf(void *buf, unsigned buflen, + const struct usb_descriptor_header **src) +{ + u8 *dest = buf; + + if (!src) + return -EINVAL; + + /* fill buffer from src[] until null descriptor ptr */ + for (; 0 != *src; src++) { + unsigned len = (*src)->bLength; + + if (len > buflen) + return -EINVAL; + memcpy(dest, *src, len); + buflen -= len; + dest += len; + } + return dest - (u8 *)buf; +} + + +/** + * usb_gadget_config_buf - builts a complete configuration descriptor + * @config: Header for the descriptor, including characteristics such + * as power requirements and number of interfaces. + * @desc: Null-terminated vector of pointers to the descriptors (interface, + * endpoint, etc) defining all functions in this device configuration. + * @buf: Buffer for the resulting configuration descriptor. + * @length: Length of buffer. If this is not big enough to hold the + * entire configuration descriptor, an error code will be returned. + * + * This copies descriptors into the response buffer, building a descriptor + * for that configuration. It returns the buffer length or a negative + * status code. The config.wTotalLength field is set to match the length + * of the result, but other descriptor fields (including power usage and + * interface count) must be set by the caller. + * + * Gadget drivers could use this when constructing a config descriptor + * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the + * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed. + */ +int usb_gadget_config_buf( + const struct usb_config_descriptor *config, + void *buf, + unsigned length, + const struct usb_descriptor_header **desc +) +{ + struct usb_config_descriptor *cp = buf; + int len; + + /* config descriptor first */ + if (length < USB_DT_CONFIG_SIZE || !desc) + return -EINVAL; + *cp = *config; + + /* then interface/endpoint/class/vendor/... */ + len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf, + length - USB_DT_CONFIG_SIZE, desc); + if (len < 0) + return len; + len += USB_DT_CONFIG_SIZE; + if (len > 0xffff) + return -EINVAL; + + /* patch up the config descriptor */ + cp->bLength = USB_DT_CONFIG_SIZE; + cp->bDescriptorType = USB_DT_CONFIG; + cp->wTotalLength = cpu_to_le16(len); + cp->bmAttributes |= USB_CONFIG_ATT_ONE; + return len; +} + +/*-------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------*/ + + +#define RBUF_LEN (1024*1024) +static int rbuf_start; +static int rbuf_len; +static __u8 rbuf[RBUF_LEN]; + +/*-------------------------------------------------------------------------*/ + +#define DRIVER_VERSION "St Patrick's Day 2004" + +static const char shortname [] = "zero"; +static const char longname [] = "YAMAHA YST-MS35D USB Speaker "; + +static const char source_sink [] = "source and sink data"; +static const char loopback [] = "loop input to output"; + +/*-------------------------------------------------------------------------*/ + +/* + * driver assumes self-powered hardware, and + * has no way for users to trigger remote wakeup. + * + * this version autoconfigures as much as possible, + * which is reasonable for most "bulk-only" drivers. + */ +static const char *EP_IN_NAME; /* source */ +static const char *EP_OUT_NAME; /* sink */ + +/*-------------------------------------------------------------------------*/ + +/* big enough to hold our biggest descriptor */ +#define USB_BUFSIZ 512 + +struct zero_dev { + spinlock_t lock; + struct usb_gadget *gadget; + struct usb_request *req; /* for control responses */ + + /* when configured, we have one of two configs: + * - source data (in to host) and sink it (out from host) + * - or loop it back (out from host back in to host) + */ + u8 config; + struct usb_ep *in_ep, *out_ep; + + /* autoresume timer */ + struct timer_list resume; +}; + +#define xprintk(d,level,fmt,args...) \ + dev_printk(level , &(d)->gadget->dev , fmt , ## args) + +#ifdef DEBUG +#define DBG(dev,fmt,args...) \ + xprintk(dev , KERN_DEBUG , fmt , ## args) +#else +#define DBG(dev,fmt,args...) \ + do { } while (0) +#endif /* DEBUG */ + +#ifdef VERBOSE +#define VDBG DBG +#else +#define VDBG(dev,fmt,args...) \ + do { } while (0) +#endif /* VERBOSE */ + +#define ERROR(dev,fmt,args...) \ + xprintk(dev , KERN_ERR , fmt , ## args) +#define WARN(dev,fmt,args...) \ + xprintk(dev , KERN_WARNING , fmt , ## args) +#define INFO(dev,fmt,args...) \ + xprintk(dev , KERN_INFO , fmt , ## args) + +/*-------------------------------------------------------------------------*/ + +static unsigned buflen = 4096; +static unsigned qlen = 32; +static unsigned pattern = 0; + +module_param (buflen, uint, S_IRUGO|S_IWUSR); +module_param (qlen, uint, S_IRUGO|S_IWUSR); +module_param (pattern, uint, S_IRUGO|S_IWUSR); + +/* + * if it's nonzero, autoresume says how many seconds to wait + * before trying to wake up the host after suspend. + */ +static unsigned autoresume = 0; +module_param (autoresume, uint, 0); + +/* + * Normally the "loopback" configuration is second (index 1) so + * it's not the default. Here's where to change that order, to + * work better with hosts where config changes are problematic. + * Or controllers (like superh) that only support one config. + */ +static int loopdefault = 0; + +module_param (loopdefault, bool, S_IRUGO|S_IWUSR); + +/*-------------------------------------------------------------------------*/ + +/* Thanks to NetChip Technologies for donating this product ID. + * + * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! + * Instead: allocate your own, using normal USB-IF procedures. + */ +#ifndef CONFIG_USB_ZERO_HNPTEST +#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ +#define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */ +#else +#define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */ +#define DRIVER_PRODUCT_NUM 0xbadd +#endif + +/*-------------------------------------------------------------------------*/ + +/* + * DESCRIPTORS ... most are static, but strings and (full) + * configuration descriptors are built on demand. + */ + +/* +#define STRING_MANUFACTURER 25 +#define STRING_PRODUCT 42 +#define STRING_SERIAL 101 +*/ +#define STRING_MANUFACTURER 1 +#define STRING_PRODUCT 2 +#define STRING_SERIAL 3 + +#define STRING_SOURCE_SINK 250 +#define STRING_LOOPBACK 251 + +/* + * This device advertises two configurations; these numbers work + * on a pxa250 as well as more flexible hardware. + */ +#define CONFIG_SOURCE_SINK 3 +#define CONFIG_LOOPBACK 2 + +/* +static struct usb_device_descriptor +device_desc = { + .bLength = sizeof device_desc, + .bDescriptorType = USB_DT_DEVICE, + + .bcdUSB = __constant_cpu_to_le16 (0x0200), + .bDeviceClass = USB_CLASS_VENDOR_SPEC, + + .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM), + .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM), + .iManufacturer = STRING_MANUFACTURER, + .iProduct = STRING_PRODUCT, + .iSerialNumber = STRING_SERIAL, + .bNumConfigurations = 2, +}; +*/ +static struct usb_device_descriptor +device_desc = { + .bLength = sizeof device_desc, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = __constant_cpu_to_le16 (0x0100), + .bDeviceClass = USB_CLASS_PER_INTERFACE, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .bcdDevice = __constant_cpu_to_le16 (0x0100), + .idVendor = __constant_cpu_to_le16 (0x0499), + .idProduct = __constant_cpu_to_le16 (0x3002), + .iManufacturer = STRING_MANUFACTURER, + .iProduct = STRING_PRODUCT, + .iSerialNumber = STRING_SERIAL, + .bNumConfigurations = 1, +}; + +static struct usb_config_descriptor +z_config = { + .bLength = sizeof z_config, + .bDescriptorType = USB_DT_CONFIG, + + /* compute wTotalLength on the fly */ + .bNumInterfaces = 2, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x40, + .bMaxPower = 0, /* self-powered */ +}; + + +static struct usb_otg_descriptor +otg_descriptor = { + .bLength = sizeof otg_descriptor, + .bDescriptorType = USB_DT_OTG, + + .bmAttributes = USB_OTG_SRP, +}; + +/* one interface in each configuration */ +#ifdef CONFIG_USB_GADGET_DUALSPEED + +/* + * usb 2.0 devices need to expose both high speed and full speed + * descriptors, unless they only run at full speed. + * + * that means alternate endpoint descriptors (bigger packets) + * and a "device qualifier" ... plus more construction options + * for the config descriptor. + */ + +static struct usb_qualifier_descriptor +dev_qualifier = { + .bLength = sizeof dev_qualifier, + .bDescriptorType = USB_DT_DEVICE_QUALIFIER, + + .bcdUSB = __constant_cpu_to_le16 (0x0200), + .bDeviceClass = USB_CLASS_VENDOR_SPEC, + + .bNumConfigurations = 2, +}; + + +struct usb_cs_as_general_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bDescriptorSubType; + __u8 bTerminalLink; + __u8 bDelay; + __u16 wFormatTag; +} __attribute__ ((packed)); + +struct usb_cs_as_format_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bDescriptorSubType; + __u8 bFormatType; + __u8 bNrChannels; + __u8 bSubframeSize; + __u8 bBitResolution; + __u8 bSamfreqType; + __u8 tLowerSamFreq[3]; + __u8 tUpperSamFreq[3]; +} __attribute__ ((packed)); + +static const struct usb_interface_descriptor +z_audio_control_if_desc = { + .bLength = sizeof z_audio_control_if_desc, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = 0x1, + .bInterfaceProtocol = 0, + .iInterface = 0, +}; + +static const struct usb_interface_descriptor +z_audio_if_desc = { + .bLength = sizeof z_audio_if_desc, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = 0x2, + .bInterfaceProtocol = 0, + .iInterface = 0, +}; + +static const struct usb_interface_descriptor +z_audio_if_desc2 = { + .bLength = sizeof z_audio_if_desc, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 1, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = 0x2, + .bInterfaceProtocol = 0, + .iInterface = 0, +}; + +static const struct usb_cs_as_general_descriptor +z_audio_cs_as_if_desc = { + .bLength = 7, + .bDescriptorType = 0x24, + + .bDescriptorSubType = 0x01, + .bTerminalLink = 0x01, + .bDelay = 0x0, + .wFormatTag = __constant_cpu_to_le16 (0x0001) +}; + + +static const struct usb_cs_as_format_descriptor +z_audio_cs_as_format_desc = { + .bLength = 0xe, + .bDescriptorType = 0x24, + + .bDescriptorSubType = 2, + .bFormatType = 1, + .bNrChannels = 1, + .bSubframeSize = 1, + .bBitResolution = 8, + .bSamfreqType = 0, + .tLowerSamFreq = {0x7e, 0x13, 0x00}, + .tUpperSamFreq = {0xe2, 0xd6, 0x00}, +}; + +static const struct usb_endpoint_descriptor +z_iso_ep = { + .bLength = 0x09, + .bDescriptorType = 0x05, + .bEndpointAddress = 0x04, + .bmAttributes = 0x09, + .wMaxPacketSize = 0x0038, + .bInterval = 0x01, + .bRefresh = 0x00, + .bSynchAddress = 0x00, +}; + +static char z_iso_ep2[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02}; + +// 9 bytes +static char z_ac_interface_header_desc[] = +{ 0x09, 0x24, 0x01, 0x00, 0x01, 0x2b, 0x00, 0x01, 0x01 }; + +// 12 bytes +static char z_0[] = {0x0c, 0x24, 0x02, 0x01, 0x01, 0x01, 0x00, 0x02, + 0x03, 0x00, 0x00, 0x00}; +// 13 bytes +static char z_1[] = {0x0d, 0x24, 0x06, 0x02, 0x01, 0x02, 0x15, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x00}; +// 9 bytes +static char z_2[] = {0x09, 0x24, 0x03, 0x03, 0x01, 0x03, 0x00, 0x02, + 0x00}; + +static char za_0[] = {0x09, 0x04, 0x01, 0x02, 0x01, 0x01, 0x02, 0x00, + 0x00}; + +static char za_1[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00}; + +static char za_2[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x01, 0x08, 0x00, + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00}; + +static char za_3[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00, + 0x00}; + +static char za_4[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02}; + +static char za_5[] = {0x09, 0x04, 0x01, 0x03, 0x01, 0x01, 0x02, 0x00, + 0x00}; + +static char za_6[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00}; + +static char za_7[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x02, 0x10, 0x00, + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00}; + +static char za_8[] = {0x09, 0x05, 0x04, 0x09, 0x70, 0x00, 0x01, 0x00, + 0x00}; + +static char za_9[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02}; + +static char za_10[] = {0x09, 0x04, 0x01, 0x04, 0x01, 0x01, 0x02, 0x00, + 0x00}; + +static char za_11[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00}; + +static char za_12[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x00, + 0x73, 0x13, 0x00, 0xe2, 0xd6, 0x00}; + +static char za_13[] = {0x09, 0x05, 0x04, 0x09, 0xe0, 0x00, 0x01, 0x00, + 0x00}; + +static char za_14[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02}; + +static char za_15[] = {0x09, 0x04, 0x01, 0x05, 0x01, 0x01, 0x02, 0x00, + 0x00}; + +static char za_16[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00}; + +static char za_17[] = {0x0e, 0x24, 0x02, 0x01, 0x01, 0x03, 0x14, 0x00, + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00}; + +static char za_18[] = {0x09, 0x05, 0x04, 0x09, 0xa8, 0x00, 0x01, 0x00, + 0x00}; + +static char za_19[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02}; + +static char za_20[] = {0x09, 0x04, 0x01, 0x06, 0x01, 0x01, 0x02, 0x00, + 0x00}; + +static char za_21[] = {0x07, 0x24, 0x01, 0x01, 0x00, 0x01, 0x00}; + +static char za_22[] = {0x0e, 0x24, 0x02, 0x01, 0x02, 0x03, 0x14, 0x00, + 0x7e, 0x13, 0x00, 0xe2, 0xd6, 0x00}; + +static char za_23[] = {0x09, 0x05, 0x04, 0x09, 0x50, 0x01, 0x01, 0x00, + 0x00}; + +static char za_24[] = {0x07, 0x25, 0x01, 0x00, 0x02, 0x00, 0x02}; + + + +static const struct usb_descriptor_header *z_function [] = { + (struct usb_descriptor_header *) &z_audio_control_if_desc, + (struct usb_descriptor_header *) &z_ac_interface_header_desc, + (struct usb_descriptor_header *) &z_0, + (struct usb_descriptor_header *) &z_1, + (struct usb_descriptor_header *) &z_2, + (struct usb_descriptor_header *) &z_audio_if_desc, + (struct usb_descriptor_header *) &z_audio_if_desc2, + (struct usb_descriptor_header *) &z_audio_cs_as_if_desc, + (struct usb_descriptor_header *) &z_audio_cs_as_format_desc, + (struct usb_descriptor_header *) &z_iso_ep, + (struct usb_descriptor_header *) &z_iso_ep2, + (struct usb_descriptor_header *) &za_0, + (struct usb_descriptor_header *) &za_1, + (struct usb_descriptor_header *) &za_2, + (struct usb_descriptor_header *) &za_3, + (struct usb_descriptor_header *) &za_4, + (struct usb_descriptor_header *) &za_5, + (struct usb_descriptor_header *) &za_6, + (struct usb_descriptor_header *) &za_7, + (struct usb_descriptor_header *) &za_8, + (struct usb_descriptor_header *) &za_9, + (struct usb_descriptor_header *) &za_10, + (struct usb_descriptor_header *) &za_11, + (struct usb_descriptor_header *) &za_12, + (struct usb_descriptor_header *) &za_13, + (struct usb_descriptor_header *) &za_14, + (struct usb_descriptor_header *) &za_15, + (struct usb_descriptor_header *) &za_16, + (struct usb_descriptor_header *) &za_17, + (struct usb_descriptor_header *) &za_18, + (struct usb_descriptor_header *) &za_19, + (struct usb_descriptor_header *) &za_20, + (struct usb_descriptor_header *) &za_21, + (struct usb_descriptor_header *) &za_22, + (struct usb_descriptor_header *) &za_23, + (struct usb_descriptor_header *) &za_24, + NULL, +}; + +/* maxpacket and other transfer characteristics vary by speed. */ +#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs)) + +#else + +/* if there's no high speed support, maxpacket doesn't change. */ +#define ep_desc(g,hs,fs) fs + +#endif /* !CONFIG_USB_GADGET_DUALSPEED */ + +static char manufacturer [40]; +//static char serial [40]; +static char serial [] = "Ser 00 em"; + +/* static strings, in UTF-8 */ +static struct usb_string strings [] = { + { STRING_MANUFACTURER, manufacturer, }, + { STRING_PRODUCT, longname, }, + { STRING_SERIAL, serial, }, + { STRING_LOOPBACK, loopback, }, + { STRING_SOURCE_SINK, source_sink, }, + { } /* end of list */ +}; + +static struct usb_gadget_strings stringtab = { + .language = 0x0409, /* en-us */ + .strings = strings, +}; + +/* + * config descriptors are also handcrafted. these must agree with code + * that sets configurations, and with code managing interfaces and their + * altsettings. other complexity may come from: + * + * - high speed support, including "other speed config" rules + * - multiple configurations + * - interfaces with alternate settings + * - embedded class or vendor-specific descriptors + * + * this handles high speed, and has a second config that could as easily + * have been an alternate interface setting (on most hardware). + * + * NOTE: to demonstrate (and test) more USB capabilities, this driver + * should include an altsetting to test interrupt transfers, including + * high bandwidth modes at high speed. (Maybe work like Intel's test + * device?) + */ +static int +config_buf (struct usb_gadget *gadget, u8 *buf, u8 type, unsigned index) +{ + int len; + const struct usb_descriptor_header **function; + + function = z_function; + len = usb_gadget_config_buf (&z_config, buf, USB_BUFSIZ, function); + if (len < 0) + return len; + ((struct usb_config_descriptor *) buf)->bDescriptorType = type; + return len; +} + +/*-------------------------------------------------------------------------*/ + +static struct usb_request * +alloc_ep_req (struct usb_ep *ep, unsigned length) +{ + struct usb_request *req; + + req = usb_ep_alloc_request (ep, GFP_ATOMIC); + if (req) { + req->length = length; + req->buf = usb_ep_alloc_buffer (ep, length, + &req->dma, GFP_ATOMIC); + if (!req->buf) { + usb_ep_free_request (ep, req); + req = NULL; + } + } + return req; +} + +static void free_ep_req (struct usb_ep *ep, struct usb_request *req) +{ + if (req->buf) + usb_ep_free_buffer (ep, req->buf, req->dma, req->length); + usb_ep_free_request (ep, req); +} + +/*-------------------------------------------------------------------------*/ + +/* optionally require specific source/sink data patterns */ + +static int +check_read_data ( + struct zero_dev *dev, + struct usb_ep *ep, + struct usb_request *req +) +{ + unsigned i; + u8 *buf = req->buf; + + for (i = 0; i < req->actual; i++, buf++) { + switch (pattern) { + /* all-zeroes has no synchronization issues */ + case 0: + if (*buf == 0) + continue; + break; + /* mod63 stays in sync with short-terminated transfers, + * or otherwise when host and gadget agree on how large + * each usb transfer request should be. resync is done + * with set_interface or set_config. + */ + case 1: + if (*buf == (u8)(i % 63)) + continue; + break; + } + ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf); + usb_ep_set_halt (ep); + return -EINVAL; + } + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static void zero_reset_config (struct zero_dev *dev) +{ + if (dev->config == 0) + return; + + DBG (dev, "reset config\n"); + + /* just disable endpoints, forcing completion of pending i/o. + * all our completion handlers free their requests in this case. + */ + if (dev->in_ep) { + usb_ep_disable (dev->in_ep); + dev->in_ep = NULL; + } + if (dev->out_ep) { + usb_ep_disable (dev->out_ep); + dev->out_ep = NULL; + } + dev->config = 0; + del_timer (&dev->resume); +} + +#define _write(f, buf, sz) (f->f_op->write(f, buf, sz, &f->f_pos)) + +static void +zero_isoc_complete (struct usb_ep *ep, struct usb_request *req) +{ + struct zero_dev *dev = ep->driver_data; + int status = req->status; + int i, j; + + switch (status) { + + case 0: /* normal completion? */ + //printk ("\nzero ---------------> isoc normal completion %d bytes\n", req->actual); + for (i=0, j=rbuf_start; iactual; i++) { + //printk ("%02x ", ((__u8*)req->buf)[i]); + rbuf[j] = ((__u8*)req->buf)[i]; + j++; + if (j >= RBUF_LEN) j=0; + } + rbuf_start = j; + //printk ("\n\n"); + + if (rbuf_len < RBUF_LEN) { + rbuf_len += req->actual; + if (rbuf_len > RBUF_LEN) { + rbuf_len = RBUF_LEN; + } + } + + break; + + /* this endpoint is normally active while we're configured */ + case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNRESET: /* request dequeued */ + case -ESHUTDOWN: /* disconnect from host */ + VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status, + req->actual, req->length); + if (ep == dev->out_ep) + check_read_data (dev, ep, req); + free_ep_req (ep, req); + return; + + case -EOVERFLOW: /* buffer overrun on read means that + * we didn't provide a big enough + * buffer. + */ + default: +#if 1 + DBG (dev, "%s complete --> %d, %d/%d\n", ep->name, + status, req->actual, req->length); +#endif + case -EREMOTEIO: /* short read */ + break; + } + + status = usb_ep_queue (ep, req, GFP_ATOMIC); + if (status) { + ERROR (dev, "kill %s: resubmit %d bytes --> %d\n", + ep->name, req->length, status); + usb_ep_set_halt (ep); + /* FIXME recover later ... somehow */ + } +} + +static struct usb_request * +zero_start_isoc_ep (struct usb_ep *ep, int gfp_flags) +{ + struct usb_request *req; + int status; + + req = alloc_ep_req (ep, 512); + if (!req) + return NULL; + + req->complete = zero_isoc_complete; + + status = usb_ep_queue (ep, req, gfp_flags); + if (status) { + struct zero_dev *dev = ep->driver_data; + + ERROR (dev, "start %s --> %d\n", ep->name, status); + free_ep_req (ep, req); + req = NULL; + } + + return req; +} + +/* change our operational config. this code must agree with the code + * that returns config descriptors, and altsetting code. + * + * it's also responsible for power management interactions. some + * configurations might not work with our current power sources. + * + * note that some device controller hardware will constrain what this + * code can do, perhaps by disallowing more than one configuration or + * by limiting configuration choices (like the pxa2xx). + */ +static int +zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags) +{ + int result = 0; + struct usb_gadget *gadget = dev->gadget; + const struct usb_endpoint_descriptor *d; + struct usb_ep *ep; + + if (number == dev->config) + return 0; + + zero_reset_config (dev); + + gadget_for_each_ep (ep, gadget) { + + if (strcmp (ep->name, "ep4") == 0) { + + d = (struct usb_endpoint_descripter *)&za_23; // isoc ep desc for audio i/f alt setting 6 + result = usb_ep_enable (ep, d); + + if (result == 0) { + ep->driver_data = dev; + dev->in_ep = ep; + + if (zero_start_isoc_ep (ep, gfp_flags) != 0) { + + dev->in_ep = ep; + continue; + } + + usb_ep_disable (ep); + result = -EIO; + } + } + + } + + dev->config = number; + return result; +} + +/*-------------------------------------------------------------------------*/ + +static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req) +{ + if (req->status || req->actual != req->length) + DBG ((struct zero_dev *) ep->driver_data, + "setup complete --> %d, %d/%d\n", + req->status, req->actual, req->length); +} + +/* + * The setup() callback implements all the ep0 functionality that's + * not handled lower down, in hardware or the hardware driver (like + * device and endpoint feature flags, and their status). It's all + * housekeeping for the gadget function we're implementing. Most of + * the work is in config-specific setup. + */ +static int +zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) +{ + struct zero_dev *dev = get_gadget_data (gadget); + struct usb_request *req = dev->req; + int value = -EOPNOTSUPP; + + /* usually this stores reply data in the pre-allocated ep0 buffer, + * but config change events will reconfigure hardware. + */ + req->zero = 0; + switch (ctrl->bRequest) { + + case USB_REQ_GET_DESCRIPTOR: + + switch (ctrl->wValue >> 8) { + + case USB_DT_DEVICE: + value = min (ctrl->wLength, (u16) sizeof device_desc); + memcpy (req->buf, &device_desc, value); + break; +#ifdef CONFIG_USB_GADGET_DUALSPEED + case USB_DT_DEVICE_QUALIFIER: + if (!gadget->is_dualspeed) + break; + value = min (ctrl->wLength, (u16) sizeof dev_qualifier); + memcpy (req->buf, &dev_qualifier, value); + break; + + case USB_DT_OTHER_SPEED_CONFIG: + if (!gadget->is_dualspeed) + break; + // FALLTHROUGH +#endif /* CONFIG_USB_GADGET_DUALSPEED */ + case USB_DT_CONFIG: + value = config_buf (gadget, req->buf, + ctrl->wValue >> 8, + ctrl->wValue & 0xff); + if (value >= 0) + value = min (ctrl->wLength, (u16) value); + break; + + case USB_DT_STRING: + /* wIndex == language code. + * this driver only handles one language, you can + * add string tables for other languages, using + * any UTF-8 characters + */ + value = usb_gadget_get_string (&stringtab, + ctrl->wValue & 0xff, req->buf); + if (value >= 0) { + value = min (ctrl->wLength, (u16) value); + } + break; + } + break; + + /* currently two configs, two speeds */ + case USB_REQ_SET_CONFIGURATION: + if (ctrl->bRequestType != 0) + goto unknown; + + spin_lock (&dev->lock); + value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC); + spin_unlock (&dev->lock); + break; + case USB_REQ_GET_CONFIGURATION: + if (ctrl->bRequestType != USB_DIR_IN) + goto unknown; + *(u8 *)req->buf = dev->config; + value = min (ctrl->wLength, (u16) 1); + break; + + /* until we add altsetting support, or other interfaces, + * only 0/0 are possible. pxa2xx only supports 0/0 (poorly) + * and already killed pending endpoint I/O. + */ + case USB_REQ_SET_INTERFACE: + + if (ctrl->bRequestType != USB_RECIP_INTERFACE) + goto unknown; + spin_lock (&dev->lock); + if (dev->config) { + u8 config = dev->config; + + /* resets interface configuration, forgets about + * previous transaction state (queued bufs, etc) + * and re-inits endpoint state (toggle etc) + * no response queued, just zero status == success. + * if we had more than one interface we couldn't + * use this "reset the config" shortcut. + */ + zero_reset_config (dev); + zero_set_config (dev, config, GFP_ATOMIC); + value = 0; + } + spin_unlock (&dev->lock); + break; + case USB_REQ_GET_INTERFACE: + if ((ctrl->bRequestType == 0x21) && (ctrl->wIndex == 0x02)) { + value = ctrl->wLength; + break; + } + else { + if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) + goto unknown; + if (!dev->config) + break; + if (ctrl->wIndex != 0) { + value = -EDOM; + break; + } + *(u8 *)req->buf = 0; + value = min (ctrl->wLength, (u16) 1); + } + break; + + /* + * These are the same vendor-specific requests supported by + * Intel's USB 2.0 compliance test devices. We exceed that + * device spec by allowing multiple-packet requests. + */ + case 0x5b: /* control WRITE test -- fill the buffer */ + if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR)) + goto unknown; + if (ctrl->wValue || ctrl->wIndex) + break; + /* just read that many bytes into the buffer */ + if (ctrl->wLength > USB_BUFSIZ) + break; + value = ctrl->wLength; + break; + case 0x5c: /* control READ test -- return the buffer */ + if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR)) + goto unknown; + if (ctrl->wValue || ctrl->wIndex) + break; + /* expect those bytes are still in the buffer; send back */ + if (ctrl->wLength > USB_BUFSIZ + || ctrl->wLength != req->length) + break; + value = ctrl->wLength; + break; + + case 0x01: // SET_CUR + case 0x02: + case 0x03: + case 0x04: + case 0x05: + value = ctrl->wLength; + break; + case 0x81: + switch (ctrl->wValue) { + case 0x0201: + case 0x0202: + ((u8*)req->buf)[0] = 0x00; + ((u8*)req->buf)[1] = 0xe3; + break; + case 0x0300: + case 0x0500: + ((u8*)req->buf)[0] = 0x00; + break; + } + //((u8*)req->buf)[0] = 0x81; + //((u8*)req->buf)[1] = 0x81; + value = ctrl->wLength; + break; + case 0x82: + switch (ctrl->wValue) { + case 0x0201: + case 0x0202: + ((u8*)req->buf)[0] = 0x00; + ((u8*)req->buf)[1] = 0xc3; + break; + case 0x0300: + case 0x0500: + ((u8*)req->buf)[0] = 0x00; + break; + } + //((u8*)req->buf)[0] = 0x82; + //((u8*)req->buf)[1] = 0x82; + value = ctrl->wLength; + break; + case 0x83: + switch (ctrl->wValue) { + case 0x0201: + case 0x0202: + ((u8*)req->buf)[0] = 0x00; + ((u8*)req->buf)[1] = 0x00; + break; + case 0x0300: + ((u8*)req->buf)[0] = 0x60; + break; + case 0x0500: + ((u8*)req->buf)[0] = 0x18; + break; + } + //((u8*)req->buf)[0] = 0x83; + //((u8*)req->buf)[1] = 0x83; + value = ctrl->wLength; + break; + case 0x84: + switch (ctrl->wValue) { + case 0x0201: + case 0x0202: + ((u8*)req->buf)[0] = 0x00; + ((u8*)req->buf)[1] = 0x01; + break; + case 0x0300: + case 0x0500: + ((u8*)req->buf)[0] = 0x08; + break; + } + //((u8*)req->buf)[0] = 0x84; + //((u8*)req->buf)[1] = 0x84; + value = ctrl->wLength; + break; + case 0x85: + ((u8*)req->buf)[0] = 0x85; + ((u8*)req->buf)[1] = 0x85; + value = ctrl->wLength; + break; + + + default: +unknown: + printk("unknown control req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, + ctrl->wValue, ctrl->wIndex, ctrl->wLength); + } + + /* respond with data transfer before status phase? */ + if (value >= 0) { + req->length = value; + req->zero = value < ctrl->wLength + && (value % gadget->ep0->maxpacket) == 0; + value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC); + if (value < 0) { + DBG (dev, "ep_queue < 0 --> %d\n", value); + req->status = 0; + zero_setup_complete (gadget->ep0, req); + } + } + + /* device either stalls (value < 0) or reports success */ + return value; +} + +static void +zero_disconnect (struct usb_gadget *gadget) +{ + struct zero_dev *dev = get_gadget_data (gadget); + unsigned long flags; + + spin_lock_irqsave (&dev->lock, flags); + zero_reset_config (dev); + + /* a more significant application might have some non-usb + * activities to quiesce here, saving resources like power + * or pushing the notification up a network stack. + */ + spin_unlock_irqrestore (&dev->lock, flags); + + /* next we may get setup() calls to enumerate new connections; + * or an unbind() during shutdown (including removing module). + */ +} + +static void +zero_autoresume (unsigned long _dev) +{ + struct zero_dev *dev = (struct zero_dev *) _dev; + int status; + + /* normally the host would be woken up for something + * more significant than just a timer firing... + */ + if (dev->gadget->speed != USB_SPEED_UNKNOWN) { + status = usb_gadget_wakeup (dev->gadget); + DBG (dev, "wakeup --> %d\n", status); + } +} + +/*-------------------------------------------------------------------------*/ + +static void +zero_unbind (struct usb_gadget *gadget) +{ + struct zero_dev *dev = get_gadget_data (gadget); + + DBG (dev, "unbind\n"); + + /* we've already been disconnected ... no i/o is active */ + if (dev->req) + free_ep_req (gadget->ep0, dev->req); + del_timer_sync (&dev->resume); + kfree (dev); + set_gadget_data (gadget, NULL); +} + +static int +zero_bind (struct usb_gadget *gadget) +{ + struct zero_dev *dev; + //struct usb_ep *ep; + + printk("binding\n"); + /* + * DRIVER POLICY CHOICE: you may want to do this differently. + * One thing to avoid is reusing a bcdDevice revision code + * with different host-visible configurations or behavior + * restrictions -- using ep1in/ep2out vs ep1out/ep3in, etc + */ + //device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201); + + + /* ok, we made sense of the hardware ... */ + dev = kmalloc (sizeof *dev, SLAB_KERNEL); + if (!dev) + return -ENOMEM; + memset (dev, 0, sizeof *dev); + spin_lock_init (&dev->lock); + dev->gadget = gadget; + set_gadget_data (gadget, dev); + + /* preallocate control response and buffer */ + dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL); + if (!dev->req) + goto enomem; + dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ, + &dev->req->dma, GFP_KERNEL); + if (!dev->req->buf) + goto enomem; + + dev->req->complete = zero_setup_complete; + + device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; + +#ifdef CONFIG_USB_GADGET_DUALSPEED + /* assume ep0 uses the same value for both speeds ... */ + dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; + + /* and that all endpoints are dual-speed */ + //hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; + //hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; +#endif + + usb_gadget_set_selfpowered (gadget); + + init_timer (&dev->resume); + dev->resume.function = zero_autoresume; + dev->resume.data = (unsigned long) dev; + + gadget->ep0->driver_data = dev; + + INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname); + INFO (dev, "using %s, OUT %s IN %s\n", gadget->name, + EP_OUT_NAME, EP_IN_NAME); + + snprintf (manufacturer, sizeof manufacturer, + UTS_SYSNAME " " UTS_RELEASE " with %s", + gadget->name); + + return 0; + +enomem: + zero_unbind (gadget); + return -ENOMEM; +} + +/*-------------------------------------------------------------------------*/ + +static void +zero_suspend (struct usb_gadget *gadget) +{ + struct zero_dev *dev = get_gadget_data (gadget); + + if (gadget->speed == USB_SPEED_UNKNOWN) + return; + + if (autoresume) { + mod_timer (&dev->resume, jiffies + (HZ * autoresume)); + DBG (dev, "suspend, wakeup in %d seconds\n", autoresume); + } else + DBG (dev, "suspend\n"); +} + +static void +zero_resume (struct usb_gadget *gadget) +{ + struct zero_dev *dev = get_gadget_data (gadget); + + DBG (dev, "resume\n"); + del_timer (&dev->resume); +} + + +/*-------------------------------------------------------------------------*/ + +static struct usb_gadget_driver zero_driver = { +#ifdef CONFIG_USB_GADGET_DUALSPEED + .speed = USB_SPEED_HIGH, +#else + .speed = USB_SPEED_FULL, +#endif + .function = (char *) longname, + .bind = zero_bind, + .unbind = zero_unbind, + + .setup = zero_setup, + .disconnect = zero_disconnect, + + .suspend = zero_suspend, + .resume = zero_resume, + + .driver = { + .name = (char *) shortname, + // .shutdown = ... + // .suspend = ... + // .resume = ... + }, +}; + +MODULE_AUTHOR ("David Brownell"); +MODULE_LICENSE ("Dual BSD/GPL"); + +static struct proc_dir_entry *pdir, *pfile; + +static int isoc_read_data (char *page, char **start, + off_t off, int count, + int *eof, void *data) +{ + int i; + static int c = 0; + static int done = 0; + static int s = 0; + +/* + printk ("\ncount: %d\n", count); + printk ("rbuf_start: %d\n", rbuf_start); + printk ("rbuf_len: %d\n", rbuf_len); + printk ("off: %d\n", off); + printk ("start: %p\n\n", *start); +*/ + if (done) { + c = 0; + done = 0; + *eof = 1; + return 0; + } + + if (c == 0) { + if (rbuf_len == RBUF_LEN) + s = rbuf_start; + else s = 0; + } + + for (i=0; i= rbuf_len) { + *eof = 1; + done = 1; + } + + + return i; +} + +static int __init init (void) +{ + + int retval = 0; + + pdir = proc_mkdir("isoc_test", NULL); + if(pdir == NULL) { + retval = -ENOMEM; + printk("Error creating dir\n"); + goto done; + } + pdir->owner = THIS_MODULE; + + pfile = create_proc_read_entry("isoc_data", + 0444, pdir, + isoc_read_data, + NULL); + if (pfile == NULL) { + retval = -ENOMEM; + printk("Error creating file\n"); + goto no_file; + } + pfile->owner = THIS_MODULE; + + return usb_gadget_register_driver (&zero_driver); + + no_file: + remove_proc_entry("isoc_data", NULL); + done: + return retval; +} +module_init (init); + +static void __exit cleanup (void) +{ + + usb_gadget_unregister_driver (&zero_driver); + + remove_proc_entry("isoc_data", pdir); + remove_proc_entry("isoc_test", NULL); +} +module_exit (cleanup); diff --git a/drivers/usb/host/dwc_otg/dwc_cfi_common.h b/drivers/usb/host/dwc_otg/dwc_cfi_common.h new file mode 100644 index 000000000000..be56af4d2223 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_cfi_common.h @@ -0,0 +1,142 @@ +/* ========================================================================== + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +#if !defined(__DWC_CFI_COMMON_H__) +#define __DWC_CFI_COMMON_H__ + +//#include + +/** + * @file + * + * This file contains the CFI specific common constants, interfaces + * (functions and macros) and structures for Linux. No PCD specific + * data structure or definition is to be included in this file. + * + */ + +/** This is a request for all Core Features */ +#define VEN_CORE_GET_FEATURES 0xB1 + +/** This is a request to get the value of a specific Core Feature */ +#define VEN_CORE_GET_FEATURE 0xB2 + +/** This command allows the host to set the value of a specific Core Feature */ +#define VEN_CORE_SET_FEATURE 0xB3 + +/** This command allows the host to set the default values of + * either all or any specific Core Feature + */ +#define VEN_CORE_RESET_FEATURES 0xB4 + +/** This command forces the PCD to write the deferred values of a Core Features */ +#define VEN_CORE_ACTIVATE_FEATURES 0xB5 + +/** This request reads a DWORD value from a register at the specified offset */ +#define VEN_CORE_READ_REGISTER 0xB6 + +/** This request writes a DWORD value into a register at the specified offset */ +#define VEN_CORE_WRITE_REGISTER 0xB7 + +/** This structure is the header of the Core Features dataset returned to + * the Host + */ +struct cfi_all_features_header { +/** The features header structure length is */ +#define CFI_ALL_FEATURES_HDR_LEN 8 + /** + * The total length of the features dataset returned to the Host + */ + uint16_t wTotalLen; + + /** + * CFI version number inBinary-Coded Decimal (i.e., 1.00 is 100H). + * This field identifies the version of the CFI Specification with which + * the device is compliant. + */ + uint16_t wVersion; + + /** The ID of the Core */ + uint16_t wCoreID; +#define CFI_CORE_ID_UDC 1 +#define CFI_CORE_ID_OTG 2 +#define CFI_CORE_ID_WUDEV 3 + + /** Number of features returned by VEN_CORE_GET_FEATURES request */ + uint16_t wNumFeatures; +} UPACKED; + +typedef struct cfi_all_features_header cfi_all_features_header_t; + +/** This structure is a header of the Core Feature descriptor dataset returned to + * the Host after the VEN_CORE_GET_FEATURES request + */ +struct cfi_feature_desc_header { +#define CFI_FEATURE_DESC_HDR_LEN 8 + + /** The feature ID */ + uint16_t wFeatureID; + + /** Length of this feature descriptor in bytes - including the + * length of the feature name string + */ + uint16_t wLength; + + /** The data length of this feature in bytes */ + uint16_t wDataLength; + + /** + * Attributes of this features + * D0: Access rights + * 0 - Read/Write + * 1 - Read only + */ + uint8_t bmAttributes; +#define CFI_FEATURE_ATTR_RO 1 +#define CFI_FEATURE_ATTR_RW 0 + + /** Length of the feature name in bytes */ + uint8_t bNameLen; + + /** The feature name buffer */ + //uint8_t *name; +} UPACKED; + +typedef struct cfi_feature_desc_header cfi_feature_desc_header_t; + +/** + * This structure describes a NULL terminated string referenced by its id field. + * It is very similar to usb_string structure but has the id field type set to 16-bit. + */ +struct cfi_string { + uint16_t id; + const uint8_t *s; +}; +typedef struct cfi_string cfi_string_t; + +#endif diff --git a/drivers/usb/host/dwc_otg/dwc_otg_attr.c b/drivers/usb/host/dwc_otg/dwc_otg_attr.c new file mode 100644 index 000000000000..26ff76f1c774 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.c @@ -0,0 +1,1316 @@ +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.c $ + * $Revision: #35 $ + * $Date: 2009/04/03 $ + * $Change: 1225160 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +/** @file + * + * The diagnostic interface will provide access to the controller for + * bringing up the hardware and testing. The Linux driver attributes + * feature will be used to provide the Linux Diagnostic + * Interface. These attributes are accessed through sysfs. + */ + +/** @page "Linux Module Attributes" + * + * The Linux module attributes feature is used to provide the Linux + * Diagnostic Interface. These attributes are accessed through sysfs. + * The diagnostic interface will provide access to the controller for + * bringing up the hardware and testing. + + The following table shows the attributes. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name Description Access
mode Returns the current mode: 0 for device mode, 1 for host mode Read
hnpcapable Gets or sets the "HNP-capable" bit in the Core USB Configuraton Register. + Read returns the current value. Read/Write
srpcapable Gets or sets the "SRP-capable" bit in the Core USB Configuraton Register. + Read returns the current value. Read/Write
hsic_connect Gets or sets the "HSIC-Connect" bit in the GLPMCFG Register. + Read returns the current value. Read/Write
inv_sel_hsic Gets or sets the "Invert Select HSIC" bit in the GLPMFG Register. + Read returns the current value. Read/Write
hnp Initiates the Host Negotiation Protocol. Read returns the status. Read/Write
srp Initiates the Session Request Protocol. Read returns the status. Read/Write
buspower Gets or sets the Power State of the bus (0 - Off or 1 - On) Read/Write
bussuspend Suspends the USB bus. Read/Write
busconnected Gets the connection status of the bus Read
gotgctl Gets or sets the Core Control Status Register. Read/Write
gusbcfg Gets or sets the Core USB Configuration Register Read/Write
grxfsiz Gets or sets the Receive FIFO Size Register Read/Write
gnptxfsiz Gets or sets the non-periodic Transmit Size Register Read/Write
gpvndctl Gets or sets the PHY Vendor Control Register Read/Write
ggpio Gets the value in the lower 16-bits of the General Purpose IO Register + or sets the upper 16 bits. Read/Write
guid Gets or sets the value of the User ID Register Read/Write
gsnpsid Gets the value of the Synopsys ID Regester Read
devspeed Gets or sets the device speed setting in the DCFG register Read/Write
enumspeed Gets the device enumeration Speed. Read
hptxfsiz Gets the value of the Host Periodic Transmit FIFO Read
hprt0 Gets or sets the value in the Host Port Control and Status Register Read/Write
regoffset Sets the register offset for the next Register Access Read/Write
regvalue Gets or sets the value of the register at the offset in the regoffset attribute. Read/Write
remote_wakeup On read, shows the status of Remote Wakeup. On write, initiates a remote + wakeup of the host. When bit 0 is 1 and Remote Wakeup is enabled, the Remote + Wakeup signalling bit in the Device Control Register is set for 1 + milli-second. Read/Write
regdump Dumps the contents of core registers. Read
spramdump Dumps the contents of core registers. Read
hcddump Dumps the current HCD state. Read
hcd_frrem Shows the average value of the Frame Remaining + field in the Host Frame Number/Frame Remaining register when an SOF interrupt + occurs. This can be used to determine the average interrupt latency. Also + shows the average Frame Remaining value for start_transfer and the "a" and + "b" sample points. The "a" and "b" sample points may be used during debugging + bto determine how long it takes to execute a section of the HCD code. Read
rd_reg_test Displays the time required to read the GNPTXFSIZ register many times + (the output shows the number of times the register is read). + Read
wr_reg_test Displays the time required to write the GNPTXFSIZ register many times + (the output shows the number of times the register is written). + Read
lpm_response Gets or sets lpm_response mode. Applicable only in device mode. + Write
sleep_local_dev Generetates sleep signaling. Applicable only in host mode. + Write
sleep_status Shows sleep status of device. + Read
+ + Example usage: + To get the current mode: + cat /sys/devices/lm0/mode + + To power down the USB: + echo 0 > /sys/devices/lm0/buspower + */ + +#include +#include +#include +#include +#include +#include +#include +#include /* permission constants */ +#include +#include +#include +#include + + +#ifdef LM_INTERFACE +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) +#include +#else +/* in 2.6.31, at least, we seem to have lost the generic LM infrastructure - + here we use definitions stolen from arm-integrator headers +*/ +#include +#endif +#elif defined(PLATFORM_INTERFACE) +#include +#endif + +#include + +#include "dwc_os.h" +#include "dwc_otg_driver.h" +#include "dwc_otg_attr.h" +#include "dwc_otg_core_if.h" +#include "dwc_otg_pcd_if.h" +#include "dwc_otg_hcd_if.h" + +/* + * MACROs for defining sysfs attribute + */ +#ifdef LM_INTERFACE + +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \ +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \ + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \ + uint32_t val; \ + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \ + return sprintf (buf, "%s = 0x%x\n", _string_, val); \ +} +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \ +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \ + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \ + uint32_t set = simple_strtoul(buf, NULL, 16); \ + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\ + return count; \ +} + +#elif defined(PCI_INTERFACE) + +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \ +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \ +{ \ + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \ + uint32_t val; \ + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \ + return sprintf (buf, "%s = 0x%x\n", _string_, val); \ +} +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \ +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \ + uint32_t set = simple_strtoul(buf, NULL, 16); \ + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\ + return count; \ +} + +#elif defined(PLATFORM_INTERFACE) + +#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \ +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \ +{ \ + struct platform_device *platform_dev = \ + container_of(_dev, struct platform_device, dev); \ + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \ + uint32_t val; \ + DWC_PRINTF("%s(%p) -> platform_dev %p, otg_dev %p\n", \ + __func__, _dev, platform_dev, otg_dev); \ + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \ + return sprintf (buf, "%s = 0x%x\n", _string_, val); \ +} +#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \ +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \ + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \ + uint32_t set = simple_strtoul(buf, NULL, 16); \ + dwc_otg_set_##_otg_attr_name_(otg_dev->core_if, set);\ + return count; \ +} +#endif + +/* + * MACROs for defining sysfs attribute for 32-bit registers + */ +#ifdef LM_INTERFACE +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \ +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \ +{ \ + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \ + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \ + uint32_t val; \ + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \ + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \ +} +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \ +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); \ + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); \ + uint32_t val = simple_strtoul(buf, NULL, 16); \ + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \ + return count; \ +} +#elif defined(PCI_INTERFACE) +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \ +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \ +{ \ + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \ + uint32_t val; \ + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \ + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \ +} +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \ +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); \ + uint32_t val = simple_strtoul(buf, NULL, 16); \ + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \ + return count; \ +} + +#elif defined(PLATFORM_INTERFACE) +#include "dwc_otg_dbg.h" +#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \ +static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \ +{ \ + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \ + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \ + uint32_t val; \ + DWC_PRINTF("%s(%p) -> platform_dev %p, otg_dev %p\n", \ + __func__, _dev, platform_dev, otg_dev); \ + val = dwc_otg_get_##_otg_attr_name_ (otg_dev->core_if); \ + return sprintf (buf, "%s = 0x%08x\n", _string_, val); \ +} +#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \ +static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct platform_device *platform_dev = container_of(_dev, struct platform_device, dev); \ + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); \ + uint32_t val = simple_strtoul(buf, NULL, 16); \ + dwc_otg_set_##_otg_attr_name_ (otg_dev->core_if, val); \ + return count; \ +} + +#endif + +#define DWC_OTG_DEVICE_ATTR_BITFIELD_RW(_otg_attr_name_,_string_) \ +DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \ +DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_string_) \ +DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store); + +#define DWC_OTG_DEVICE_ATTR_BITFIELD_RO(_otg_attr_name_,_string_) \ +DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_string_) \ +DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL); + +#define DWC_OTG_DEVICE_ATTR_REG32_RW(_otg_attr_name_,_addr_,_string_) \ +DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \ +DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_string_) \ +DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store); + +#define DWC_OTG_DEVICE_ATTR_REG32_RO(_otg_attr_name_,_addr_,_string_) \ +DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_string_) \ +DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL); + +/** @name Functions for Show/Store of Attributes */ +/**@{*/ + +/** + * Show the register offset of the Register Access. + */ +static ssize_t regoffset_show(struct device *_dev, + struct device_attribute *attr, char *buf) +{ +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = container_of(_dev, + struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + + return snprintf(buf, sizeof("0xFFFFFFFF\n") + 1, "0x%08x\n", + otg_dev->reg_offset); +} + +/** + * Set the register offset for the next Register Access Read/Write + */ +static ssize_t regoffset_store(struct device *_dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = container_of(_dev, + struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + + uint32_t offset = simple_strtoul(buf, NULL, 16); + if (offset < SZ_256K) { + otg_dev->reg_offset = offset; + } else { + dev_err(_dev, "invalid offset\n"); + } + + return count; +} + +DEVICE_ATTR(regoffset, S_IRUGO | S_IWUSR, regoffset_show, regoffset_store); + +/** + * Show the value of the register at the offset in the reg_offset + * attribute. + */ +static ssize_t regvalue_show(struct device *_dev, + struct device_attribute *attr, char *buf) +{ +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + + uint32_t val; + volatile uint32_t *addr; + + if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) { + /* Calculate the address */ + addr = (uint32_t *) (otg_dev->reg_offset + + (uint8_t *) otg_dev->base); + val = dwc_read_reg32(addr); + return snprintf(buf, + sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n") + 1, + "Reg@0x%06x = 0x%08x\n", otg_dev->reg_offset, + val); + } else { + dev_err(_dev, "Invalid offset (0x%0x)\n", otg_dev->reg_offset); + return sprintf(buf, "invalid offset\n"); + } +} + +/** + * Store the value in the register at the offset in the reg_offset + * attribute. + * + */ +static ssize_t regvalue_store(struct device *_dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + + volatile uint32_t *addr; + uint32_t val = simple_strtoul(buf, NULL, 16); + //dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val); + if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) { + /* Calculate the address */ + addr = (uint32_t *) (otg_dev->reg_offset + + (uint8_t *) otg_dev->base); + dwc_write_reg32(addr, val); + } else { + dev_err(_dev, "Invalid Register Offset (0x%08x)\n", + otg_dev->reg_offset); + } + return count; +} + +DEVICE_ATTR(regvalue, S_IRUGO | S_IWUSR, regvalue_show, regvalue_store); + +/* + * Attributes + */ +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(mode, "Mode"); +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hnpcapable, "HNPCapable"); +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(srpcapable, "Mode"); +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hsic_connect, "HSIC Connect"); +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(inv_sel_hsic, "Invert Select HSIC"); + +//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(buspower,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode"); +//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(bussuspend,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode"); +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(busconnected, "Bus Connected"); + +DWC_OTG_DEVICE_ATTR_REG32_RW(gotgctl, 0, "GOTGCTL"); +DWC_OTG_DEVICE_ATTR_REG32_RW(gusbcfg, + &(otg_dev->core_if->core_global_regs->gusbcfg), + "GUSBCFG"); +DWC_OTG_DEVICE_ATTR_REG32_RW(grxfsiz, + &(otg_dev->core_if->core_global_regs->grxfsiz), + "GRXFSIZ"); +DWC_OTG_DEVICE_ATTR_REG32_RW(gnptxfsiz, + &(otg_dev->core_if->core_global_regs->gnptxfsiz), + "GNPTXFSIZ"); +DWC_OTG_DEVICE_ATTR_REG32_RW(gpvndctl, + &(otg_dev->core_if->core_global_regs->gpvndctl), + "GPVNDCTL"); +DWC_OTG_DEVICE_ATTR_REG32_RW(ggpio, + &(otg_dev->core_if->core_global_regs->ggpio), + "GGPIO"); +DWC_OTG_DEVICE_ATTR_REG32_RW(guid, &(otg_dev->core_if->core_global_regs->guid), + "GUID"); +DWC_OTG_DEVICE_ATTR_REG32_RO(gsnpsid, + &(otg_dev->core_if->core_global_regs->gsnpsid), + "GSNPSID"); +DWC_OTG_DEVICE_ATTR_BITFIELD_RW(devspeed, "Device Speed"); +DWC_OTG_DEVICE_ATTR_BITFIELD_RO(enumspeed, "Device Enumeration Speed"); + +DWC_OTG_DEVICE_ATTR_REG32_RO(hptxfsiz, + &(otg_dev->core_if->core_global_regs->hptxfsiz), + "HPTXFSIZ"); +DWC_OTG_DEVICE_ATTR_REG32_RW(hprt0, otg_dev->core_if->host_if->hprt0, "HPRT0"); + +/** + * @todo Add code to initiate the HNP. + */ +/** + * Show the HNP status bit + */ +static ssize_t hnp_show(struct device *_dev, + struct device_attribute *attr, char *buf) +{ +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + return sprintf(buf, "HstNegScs = 0x%x\n", + dwc_otg_get_hnpstatus(otg_dev->core_if)); +} + +/** + * Set the HNP Request bit + */ +static ssize_t hnp_store(struct device *_dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + uint32_t in = simple_strtoul(buf, NULL, 16); + dwc_otg_set_hnpreq(otg_dev->core_if, in); + return count; +} + +DEVICE_ATTR(hnp, 0644, hnp_show, hnp_store); + +/** + * @todo Add code to initiate the SRP. + */ +/** + * Show the SRP status bit + */ +static ssize_t srp_show(struct device *_dev, + struct device_attribute *attr, char *buf) +{ +#ifndef DWC_HOST_ONLY +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + return sprintf(buf, "SesReqScs = 0x%x\n", + dwc_otg_get_srpstatus(otg_dev->core_if)); +#else + return sprintf(buf, "Host Only Mode!\n"); +#endif +} + +/** + * Set the SRP Request bit + */ +static ssize_t srp_store(struct device *_dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifndef DWC_HOST_ONLY +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + dwc_otg_pcd_initiate_srp(otg_dev->pcd); +#endif + return count; +} + +DEVICE_ATTR(srp, 0644, srp_show, srp_store); + +/** + * @todo Need to do more for power on/off? + */ +/** + * Show the Bus Power status + */ +static ssize_t buspower_show(struct device *_dev, + struct device_attribute *attr, char *buf) +{ +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + return sprintf(buf, "Bus Power = 0x%x\n", + dwc_otg_get_prtpower(otg_dev->core_if)); +} + +/** + * Set the Bus Power status + */ +static ssize_t buspower_store(struct device *_dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + uint32_t on = simple_strtoul(buf, NULL, 16); + dwc_otg_set_prtpower(otg_dev->core_if, on); + return count; +} + +DEVICE_ATTR(buspower, 0644, buspower_show, buspower_store); + +/** + * @todo Need to do more for suspend? + */ +/** + * Show the Bus Suspend status + */ +static ssize_t bussuspend_show(struct device *_dev, + struct device_attribute *attr, char *buf) +{ +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + + return sprintf(buf, "Bus Suspend = 0x%x\n", + dwc_otg_get_prtsuspend(otg_dev->core_if)); +} + +/** + * Set the Bus Suspend status + */ +static ssize_t bussuspend_store(struct device *_dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + + uint32_t in = simple_strtoul(buf, NULL, 16); + dwc_otg_set_prtsuspend(otg_dev->core_if, in); + return count; +} + +DEVICE_ATTR(bussuspend, 0644, bussuspend_show, bussuspend_store); + +/** + * Show the status of Remote Wakeup. + */ +static ssize_t remote_wakeup_show(struct device *_dev, + struct device_attribute *attr, char *buf) +{ +#ifndef DWC_HOST_ONLY +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + + return sprintf(buf, + "Remote Wakeup Sig = %d Enabled = %d LPM Remote Wakeup = %d\n", + dwc_otg_get_remotewakesig(otg_dev->core_if), + dwc_otg_pcd_get_rmwkup_enable(otg_dev->pcd), + dwc_otg_get_lpm_remotewakeenabled(otg_dev->core_if)); +#else + return sprintf(buf, "Host Only Mode!\n"); +#endif /* DWC_HOST_ONLY */ +} + +/** + * Initiate a remote wakeup of the host. The Device control register + * Remote Wakeup Signal bit is written if the PCD Remote wakeup enable + * flag is set. + * + */ +static ssize_t remote_wakeup_store(struct device *_dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifndef DWC_HOST_ONLY +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + + uint32_t val = simple_strtoul(buf, NULL, 16); + + if (val & 1) { + dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 1); + } else { + dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 0); + } +#endif /* DWC_HOST_ONLY */ + return count; +} + +DEVICE_ATTR(remote_wakeup, S_IRUGO | S_IWUSR, remote_wakeup_show, + remote_wakeup_store); + +/** + * Dump global registers and either host or device registers (depending on the + * current mode of the core). + */ +static ssize_t regdump_show(struct device *_dev, + struct device_attribute *attr, char *buf) +{ +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + + dwc_otg_dump_global_registers(otg_dev->core_if); + if (dwc_otg_is_host_mode(otg_dev->core_if)) { + dwc_otg_dump_host_registers(otg_dev->core_if); + } else { + dwc_otg_dump_dev_registers(otg_dev->core_if); + + } + return sprintf(buf, "Register Dump\n"); +} + +DEVICE_ATTR(regdump, S_IRUGO | S_IWUSR, regdump_show, 0); + +/** + * Dump global registers and either host or device registers (depending on the + * current mode of the core). + */ +static ssize_t spramdump_show(struct device *_dev, + struct device_attribute *attr, char *buf) +{ +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + + dwc_otg_dump_spram(otg_dev->core_if); + + return sprintf(buf, "SPRAM Dump\n"); +} + +DEVICE_ATTR(spramdump, S_IRUGO | S_IWUSR, spramdump_show, 0); + +/** + * Dump the current hcd state. + */ +static ssize_t hcddump_show(struct device *_dev, + struct device_attribute *attr, char *buf) +{ +#ifndef DWC_DEVICE_ONLY +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + + dwc_otg_hcd_dump_state(otg_dev->hcd); +#endif /* DWC_DEVICE_ONLY */ + return sprintf(buf, "HCD Dump\n"); +} + +DEVICE_ATTR(hcddump, S_IRUGO | S_IWUSR, hcddump_show, 0); + +/** + * Dump the average frame remaining at SOF. This can be used to + * determine average interrupt latency. Frame remaining is also shown for + * start transfer and two additional sample points. + */ +static ssize_t hcd_frrem_show(struct device *_dev, + struct device_attribute *attr, char *buf) +{ +#ifndef DWC_DEVICE_ONLY +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + + dwc_otg_hcd_dump_frrem(otg_dev->hcd); +#endif /* DWC_DEVICE_ONLY */ + return sprintf(buf, "HCD Dump Frame Remaining\n"); +} + +DEVICE_ATTR(hcd_frrem, S_IRUGO | S_IWUSR, hcd_frrem_show, 0); + +/** + * Displays the time required to read the GNPTXFSIZ register many times (the + * output shows the number of times the register is read). + */ +#define RW_REG_COUNT 10000000 +#define MSEC_PER_JIFFIE 1000/HZ +static ssize_t rd_reg_test_show(struct device *_dev, + struct device_attribute *attr, char *buf) +{ +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + + int i; + int time; + int start_jiffies; + + printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n", + HZ, MSEC_PER_JIFFIE, loops_per_jiffy); + start_jiffies = jiffies; + for (i = 0; i < RW_REG_COUNT; i++) { + dwc_otg_get_gnptxfsiz(otg_dev->core_if); + } + time = jiffies - start_jiffies; + return sprintf(buf, + "Time to read GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n", + RW_REG_COUNT, time * MSEC_PER_JIFFIE, time); +} + +DEVICE_ATTR(rd_reg_test, S_IRUGO | S_IWUSR, rd_reg_test_show, 0); + +/** + * Displays the time required to write the GNPTXFSIZ register many times (the + * output shows the number of times the register is written). + */ +static ssize_t wr_reg_test_show(struct device *_dev, + struct device_attribute *attr, char *buf) +{ +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + + uint32_t reg_val; + int i; + int time; + int start_jiffies; + + printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n", + HZ, MSEC_PER_JIFFIE, loops_per_jiffy); + reg_val = dwc_otg_get_gnptxfsiz(otg_dev->core_if); + start_jiffies = jiffies; + for (i = 0; i < RW_REG_COUNT; i++) { + dwc_otg_set_gnptxfsiz(otg_dev->core_if, reg_val); + } + time = jiffies - start_jiffies; + return sprintf(buf, + "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n", + RW_REG_COUNT, time * MSEC_PER_JIFFIE, time); +} + +DEVICE_ATTR(wr_reg_test, S_IRUGO | S_IWUSR, wr_reg_test_show, 0); + +#ifdef CONFIG_USB_DWC_OTG_LPM + +/** +* Show the lpm_response attribute. +*/ +static ssize_t lpmresp_show(struct device *_dev, + struct device_attribute *attr, char *buf) +{ +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + + if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if)) + return sprintf(buf, "** LPM is DISABLED **\n"); + + if (!dwc_otg_is_device_mode(otg_dev->core_if)) { + return sprintf(buf, "** Current mode is not device mode\n"); + } + return sprintf(buf, "lpm_response = %d\n", + dwc_otg_get_lpmresponse(otg_dev->core_if)); +} + +/** +* Store the lpm_response attribute. +*/ +static ssize_t lpmresp_store(struct device *_dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + + uint32_t val = simple_strtoul(buf, NULL, 16); + + if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if)) { + return 0; + } + + if (!dwc_otg_is_device_mode(otg_dev->core_if)) { + return 0; + } + + dwc_otg_set_lpmresponse(otg_dev->core_if, val); + return count; +} + +DEVICE_ATTR(lpm_response, S_IRUGO | S_IWUSR, lpmresp_show, lpmresp_store); + +/** +* Show the sleep_status attribute. +*/ +static ssize_t sleepstatus_show(struct device *_dev, + struct device_attribute *attr, char *buf) +{ +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + + + return sprintf(buf, "Sleep Status = %d\n", + dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if)); +} + +/** + * Store the sleep_status attribure. + */ +static ssize_t sleepstatus_store(struct device *_dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef LM_INTERFACE + struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev); + dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platform_dev = + container_of(_dev, struct platform_device, dev); + dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev); +#endif + + dwc_otg_core_if_t *core_if = otg_dev->core_if; + + if (dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if)) { + if (dwc_otg_is_host_mode(core_if)) { + + DWC_PRINTF("Host initiated resume\n"); + dwc_otg_set_prtresume(otg_dev->core_if, 1); + } + } + + return count; +} + +DEVICE_ATTR(sleep_status, S_IRUGO | S_IWUSR, sleepstatus_show, + sleepstatus_store); + +#endif /* CONFIG_USB_DWC_OTG_LPM_ENABLE */ + +/**@}*/ + +/** + * Create the device files + */ +void dwc_otg_attr_create ( +#ifdef LM_INTERFACE + struct lm_device *dev +#elif defined(PCI_INTERFACE) + struct pci_dev *dev +#elif defined(PLATFORM_INTERFACE) + struct platform_device *dev +#endif + ) + +{ + int error; + + error = device_create_file(&dev->dev, &dev_attr_regoffset); + error = device_create_file(&dev->dev, &dev_attr_regvalue); + error = device_create_file(&dev->dev, &dev_attr_mode); + error = device_create_file(&dev->dev, &dev_attr_hnpcapable); + error = device_create_file(&dev->dev, &dev_attr_srpcapable); + error = device_create_file(&dev->dev, &dev_attr_hsic_connect); + error = device_create_file(&dev->dev, &dev_attr_inv_sel_hsic); + error = device_create_file(&dev->dev, &dev_attr_hnp); + error = device_create_file(&dev->dev, &dev_attr_srp); + error = device_create_file(&dev->dev, &dev_attr_buspower); + error = device_create_file(&dev->dev, &dev_attr_bussuspend); + error = device_create_file(&dev->dev, &dev_attr_busconnected); + error = device_create_file(&dev->dev, &dev_attr_gotgctl); + error = device_create_file(&dev->dev, &dev_attr_gusbcfg); + error = device_create_file(&dev->dev, &dev_attr_grxfsiz); + error = device_create_file(&dev->dev, &dev_attr_gnptxfsiz); + error = device_create_file(&dev->dev, &dev_attr_gpvndctl); + error = device_create_file(&dev->dev, &dev_attr_ggpio); + error = device_create_file(&dev->dev, &dev_attr_guid); + error = device_create_file(&dev->dev, &dev_attr_gsnpsid); + error = device_create_file(&dev->dev, &dev_attr_devspeed); + error = device_create_file(&dev->dev, &dev_attr_enumspeed); + error = device_create_file(&dev->dev, &dev_attr_hptxfsiz); + error = device_create_file(&dev->dev, &dev_attr_hprt0); + error = device_create_file(&dev->dev, &dev_attr_remote_wakeup); + error = device_create_file(&dev->dev, &dev_attr_regdump); + error = device_create_file(&dev->dev, &dev_attr_spramdump); + error = device_create_file(&dev->dev, &dev_attr_hcddump); + error = device_create_file(&dev->dev, &dev_attr_hcd_frrem); + error = device_create_file(&dev->dev, &dev_attr_rd_reg_test); + error = device_create_file(&dev->dev, &dev_attr_wr_reg_test); +#ifdef CONFIG_USB_DWC_OTG_LPM + error = device_create_file(&dev->dev, &dev_attr_lpm_response); + error = device_create_file(&dev->dev, &dev_attr_sleep_status); +#endif +} + +/** + * Remove the device files + */ +void dwc_otg_attr_remove ( +#ifdef LM_INTERFACE + struct lm_device *dev +#elif defined(PCI_INTERFACE) + struct pci_dev *dev +#elif defined(PLATFORM_INTERFACE) + struct platform_device *dev +#endif + ) + +{ + device_remove_file(&dev->dev, &dev_attr_regoffset); + device_remove_file(&dev->dev, &dev_attr_regvalue); + device_remove_file(&dev->dev, &dev_attr_mode); + device_remove_file(&dev->dev, &dev_attr_hnpcapable); + device_remove_file(&dev->dev, &dev_attr_srpcapable); + device_remove_file(&dev->dev, &dev_attr_hsic_connect); + device_remove_file(&dev->dev, &dev_attr_inv_sel_hsic); + device_remove_file(&dev->dev, &dev_attr_hnp); + device_remove_file(&dev->dev, &dev_attr_srp); + device_remove_file(&dev->dev, &dev_attr_buspower); + device_remove_file(&dev->dev, &dev_attr_bussuspend); + device_remove_file(&dev->dev, &dev_attr_busconnected); + device_remove_file(&dev->dev, &dev_attr_gotgctl); + device_remove_file(&dev->dev, &dev_attr_gusbcfg); + device_remove_file(&dev->dev, &dev_attr_grxfsiz); + device_remove_file(&dev->dev, &dev_attr_gnptxfsiz); + device_remove_file(&dev->dev, &dev_attr_gpvndctl); + device_remove_file(&dev->dev, &dev_attr_ggpio); + device_remove_file(&dev->dev, &dev_attr_guid); + device_remove_file(&dev->dev, &dev_attr_gsnpsid); + device_remove_file(&dev->dev, &dev_attr_devspeed); + device_remove_file(&dev->dev, &dev_attr_enumspeed); + device_remove_file(&dev->dev, &dev_attr_hptxfsiz); + device_remove_file(&dev->dev, &dev_attr_hprt0); + device_remove_file(&dev->dev, &dev_attr_remote_wakeup); + device_remove_file(&dev->dev, &dev_attr_regdump); + device_remove_file(&dev->dev, &dev_attr_spramdump); + device_remove_file(&dev->dev, &dev_attr_hcddump); + device_remove_file(&dev->dev, &dev_attr_hcd_frrem); + device_remove_file(&dev->dev, &dev_attr_rd_reg_test); + device_remove_file(&dev->dev, &dev_attr_wr_reg_test); +#ifdef CONFIG_USB_DWC_OTG_LPM + device_remove_file(&dev->dev, &dev_attr_lpm_response); + device_remove_file(&dev->dev, &dev_attr_sleep_status); +#endif +} diff --git a/drivers/usb/host/dwc_otg/dwc_otg_attr.h b/drivers/usb/host/dwc_otg/dwc_otg_attr.h new file mode 100644 index 000000000000..b59651d50875 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.h @@ -0,0 +1,88 @@ +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_attr.h $ + * $Revision: #11 $ + * $Date: 2009/04/03 $ + * $Change: 1225160 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +#if !defined(__DWC_OTG_ATTR_H__) +#define __DWC_OTG_ATTR_H__ + +/** @file + * This file contains the interface to the Linux device attributes. + */ +extern struct device_attribute dev_attr_regoffset; +extern struct device_attribute dev_attr_regvalue; + +extern struct device_attribute dev_attr_mode; +extern struct device_attribute dev_attr_hnpcapable; +extern struct device_attribute dev_attr_srpcapable; +extern struct device_attribute dev_attr_hnp; +extern struct device_attribute dev_attr_srp; +extern struct device_attribute dev_attr_buspower; +extern struct device_attribute dev_attr_bussuspend; +extern struct device_attribute dev_attr_busconnected; +extern struct device_attribute dev_attr_gotgctl; +extern struct device_attribute dev_attr_gusbcfg; +extern struct device_attribute dev_attr_grxfsiz; +extern struct device_attribute dev_attr_gnptxfsiz; +extern struct device_attribute dev_attr_gpvndctl; +extern struct device_attribute dev_attr_ggpio; +extern struct device_attribute dev_attr_guid; +extern struct device_attribute dev_attr_gsnpsid; +extern struct device_attribute dev_attr_devspeed; +extern struct device_attribute dev_attr_enumspeed; +extern struct device_attribute dev_attr_hptxfsiz; +extern struct device_attribute dev_attr_hprt0; +#ifdef CONFIG_USB_DWC_OTG_LPM +extern struct device_attribute dev_attr_lpm_response; +extern struct device_attribute dev_attr_sleep_local_dev; +extern struct device_attribute devi_attr_sleep_status; +#endif + +void dwc_otg_attr_create ( +#ifdef LM_INTERFACE + struct lm_device *dev +#elif defined(PCI_INTERFACE) + struct pci_dev *dev +#elif defined(PLATFORM_INTERFACE) + struct platform_device *dev +#endif + ); + +void dwc_otg_attr_remove ( +#ifdef LM_INTERFACE + struct lm_device *dev +#elif defined(PCI_INTERFACE) + struct pci_dev *dev +#elif defined(PLATFORM_INTERFACE) + struct platform_device *dev +#endif + ); +#endif diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cfi.c b/drivers/usb/host/dwc_otg/dwc_otg_cfi.c new file mode 100644 index 000000000000..7fe725545b48 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_cfi.c @@ -0,0 +1,1876 @@ +/* ========================================================================== + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +/** @file + * + * This file contains the most of the CFI implementation for the OTG. + */ + +#ifdef DWC_UTE_CFI + +#include "dwc_otg_pcd.h" +#include "dwc_otg_cfi.h" + +/** This definition should actually migrate to the Portability Library */ +#define DWC_CONSTANT_CPU_TO_LE16(x) (x) + +extern dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex); + +static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen); +static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen, + struct dwc_otg_pcd *pcd, + struct cfi_usb_ctrlrequest *ctrl_req); +static int cfi_set_feature_value(struct dwc_otg_pcd *pcd); +static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd, + struct cfi_usb_ctrlrequest *req); +static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd, + struct cfi_usb_ctrlrequest *req); +static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd, + struct cfi_usb_ctrlrequest *req); +static int cfi_preproc_reset(struct dwc_otg_pcd *pcd, + struct cfi_usb_ctrlrequest *req); +static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep); + +static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if); +static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue); +static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue); + +static uint8_t resize_fifos(dwc_otg_core_if_t * core_if); + +/** This is the header of the all features descriptor */ +static cfi_all_features_header_t all_props_desc_header = { + .wVersion = DWC_CONSTANT_CPU_TO_LE16(0x100), + .wCoreID = DWC_CONSTANT_CPU_TO_LE16(CFI_CORE_ID_OTG), + .wNumFeatures = DWC_CONSTANT_CPU_TO_LE16(9), +}; + +/** This is an array of statically allocated feature descriptors */ +static cfi_feature_desc_header_t prop_descs[] = { + + /* FT_ID_DMA_MODE */ + { + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_MODE), + .bmAttributes = CFI_FEATURE_ATTR_RW, + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(1), + }, + + /* FT_ID_DMA_BUFFER_SETUP */ + { + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFFER_SETUP), + .bmAttributes = CFI_FEATURE_ATTR_RW, + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6), + }, + + /* FT_ID_DMA_BUFF_ALIGN */ + { + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_BUFF_ALIGN), + .bmAttributes = CFI_FEATURE_ATTR_RW, + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2), + }, + + /* FT_ID_DMA_CONCAT_SETUP */ + { + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CONCAT_SETUP), + .bmAttributes = CFI_FEATURE_ATTR_RW, + //.wDataLength = DWC_CONSTANT_CPU_TO_LE16(6), + }, + + /* FT_ID_DMA_CIRCULAR */ + { + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DMA_CIRCULAR), + .bmAttributes = CFI_FEATURE_ATTR_RW, + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6), + }, + + /* FT_ID_THRESHOLD_SETUP */ + { + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_THRESHOLD_SETUP), + .bmAttributes = CFI_FEATURE_ATTR_RW, + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(6), + }, + + /* FT_ID_DFIFO_DEPTH */ + { + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_DFIFO_DEPTH), + .bmAttributes = CFI_FEATURE_ATTR_RO, + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2), + }, + + /* FT_ID_TX_FIFO_DEPTH */ + { + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_TX_FIFO_DEPTH), + .bmAttributes = CFI_FEATURE_ATTR_RW, + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2), + }, + + /* FT_ID_RX_FIFO_DEPTH */ + { + .wFeatureID = DWC_CONSTANT_CPU_TO_LE16(FT_ID_RX_FIFO_DEPTH), + .bmAttributes = CFI_FEATURE_ATTR_RW, + .wDataLength = DWC_CONSTANT_CPU_TO_LE16(2), + } +}; + +/** The table of feature names */ +cfi_string_t prop_name_table[] = { + {FT_ID_DMA_MODE, "dma_mode"}, + {FT_ID_DMA_BUFFER_SETUP, "buffer_setup"}, + {FT_ID_DMA_BUFF_ALIGN, "buffer_align"}, + {FT_ID_DMA_CONCAT_SETUP, "concat_setup"}, + {FT_ID_DMA_CIRCULAR, "buffer_circular"}, + {FT_ID_THRESHOLD_SETUP, "threshold_setup"}, + {FT_ID_DFIFO_DEPTH, "dfifo_depth"}, + {FT_ID_TX_FIFO_DEPTH, "txfifo_depth"}, + {FT_ID_RX_FIFO_DEPTH, "rxfifo_depth"}, + {} +}; + +/************************************************************************/ + +/** + * Returns the name of the feature by its ID + * or NULL if no featute ID matches. + * + */ +const uint8_t *get_prop_name(uint16_t prop_id, int *len) +{ + cfi_string_t *pstr; + *len = 0; + + for (pstr = prop_name_table; pstr && pstr->s; pstr++) { + if (pstr->id == prop_id) { + *len = DWC_STRLEN(pstr->s); + return pstr->s; + } + } + return NULL; +} + +/** + * This function handles all CFI specific control requests. + * + * Return a negative value to stall the DCE. + */ +int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl) +{ + int retval = 0; + dwc_otg_pcd_ep_t *ep = NULL; + cfiobject_t *cfi = pcd->cfi; + struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd); + uint16_t wLen = DWC_LE16_TO_CPU(&ctrl->wLength); + uint16_t wValue = DWC_LE16_TO_CPU(&ctrl->wValue); + uint16_t wIndex = DWC_LE16_TO_CPU(&ctrl->wIndex); + uint32_t regaddr = 0; + uint32_t regval = 0; + + /* Save this Control Request in the CFI object. + * The data field will be assigned in the data stage completion CB function. + */ + cfi->ctrl_req = *ctrl; + cfi->ctrl_req.data = NULL; + + cfi->need_gadget_att = 0; + cfi->need_status_in_complete = 0; + + switch (ctrl->bRequest) { + case VEN_CORE_GET_FEATURES: + retval = cfi_core_features_buf(cfi->buf_in.buf, CFI_IN_BUF_LEN); + if (retval >= 0) { + //dump_msg(cfi->buf_in.buf, retval); + ep = &pcd->ep0; + + retval = min((uint16_t) retval, wLen); + /* Transfer this buffer to the host through the EP0-IN EP */ + ep->dwc_ep.dma_addr = cfi->buf_in.addr; + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf; + ep->dwc_ep.xfer_buff = cfi->buf_in.buf; + ep->dwc_ep.xfer_len = retval; + ep->dwc_ep.xfer_count = 0; + ep->dwc_ep.sent_zlp = 0; + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len; + + pcd->ep0_pending = 1; + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep); + } + retval = 0; + break; + + case VEN_CORE_GET_FEATURE: + CFI_INFO("VEN_CORE_GET_FEATURE\n"); + retval = cfi_get_feature_value(cfi->buf_in.buf, CFI_IN_BUF_LEN, + pcd, ctrl); + if (retval >= 0) { + ep = &pcd->ep0; + + retval = min((uint16_t) retval, wLen); + /* Transfer this buffer to the host through the EP0-IN EP */ + ep->dwc_ep.dma_addr = cfi->buf_in.addr; + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf; + ep->dwc_ep.xfer_buff = cfi->buf_in.buf; + ep->dwc_ep.xfer_len = retval; + ep->dwc_ep.xfer_count = 0; + ep->dwc_ep.sent_zlp = 0; + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len; + + pcd->ep0_pending = 1; + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep); + } + CFI_INFO("VEN_CORE_GET_FEATURE=%d\n", retval); + dump_msg(cfi->buf_in.buf, retval); + break; + + case VEN_CORE_SET_FEATURE: + CFI_INFO("VEN_CORE_SET_FEATURE\n"); + /* Set up an XFER to get the data stage of the control request, + * which is the new value of the feature to be modified. + */ + ep = &pcd->ep0; + ep->dwc_ep.is_in = 0; + ep->dwc_ep.dma_addr = cfi->buf_out.addr; + ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf; + ep->dwc_ep.xfer_buff = cfi->buf_out.buf; + ep->dwc_ep.xfer_len = wLen; + ep->dwc_ep.xfer_count = 0; + ep->dwc_ep.sent_zlp = 0; + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len; + + pcd->ep0_pending = 1; + /* Read the control write's data stage */ + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep); + retval = 0; + break; + + case VEN_CORE_RESET_FEATURES: + CFI_INFO("VEN_CORE_RESET_FEATURES\n"); + cfi->need_gadget_att = 1; + cfi->need_status_in_complete = 1; + retval = cfi_preproc_reset(pcd, ctrl); + CFI_INFO("VEN_CORE_RESET_FEATURES = (%d)\n", retval); + break; + + case VEN_CORE_ACTIVATE_FEATURES: + CFI_INFO("VEN_CORE_ACTIVATE_FEATURES\n"); + break; + + case VEN_CORE_READ_REGISTER: + CFI_INFO("VEN_CORE_READ_REGISTER\n"); + /* wValue optionally contains the HI WORD of the register offset and + * wIndex contains the LOW WORD of the register offset + */ + if (wValue == 0) { + /* @TODO - MAS - fix the access to the base field */ + regaddr = 0; + //regaddr = (uint32_t) pcd->otg_dev->base; + //GET_CORE_IF(pcd)->co + regaddr |= wIndex; + } else { + regaddr = (wValue << 16) | wIndex; + } + + /* Read a 32-bit value of the memory at the regaddr */ + regval = dwc_read_reg32((uint32_t *) regaddr); + + ep = &pcd->ep0; + dwc_memcpy(cfi->buf_in.buf, ®val, sizeof(uint32_t)); + ep->dwc_ep.is_in = 1; + ep->dwc_ep.dma_addr = cfi->buf_in.addr; + ep->dwc_ep.start_xfer_buff = cfi->buf_in.buf; + ep->dwc_ep.xfer_buff = cfi->buf_in.buf; + ep->dwc_ep.xfer_len = wLen; + ep->dwc_ep.xfer_count = 0; + ep->dwc_ep.sent_zlp = 0; + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len; + + pcd->ep0_pending = 1; + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep); + cfi->need_gadget_att = 0; + retval = 0; + break; + + case VEN_CORE_WRITE_REGISTER: + CFI_INFO("VEN_CORE_WRITE_REGISTER\n"); + /* Set up an XFER to get the data stage of the control request, + * which is the new value of the register to be modified. + */ + ep = &pcd->ep0; + ep->dwc_ep.is_in = 0; + ep->dwc_ep.dma_addr = cfi->buf_out.addr; + ep->dwc_ep.start_xfer_buff = cfi->buf_out.buf; + ep->dwc_ep.xfer_buff = cfi->buf_out.buf; + ep->dwc_ep.xfer_len = wLen; + ep->dwc_ep.xfer_count = 0; + ep->dwc_ep.sent_zlp = 0; + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len; + + pcd->ep0_pending = 1; + /* Read the control write's data stage */ + dwc_otg_ep0_start_transfer(coreif, &ep->dwc_ep); + retval = 0; + break; + + default: + retval = -DWC_E_NOT_SUPPORTED; + break; + } + + return retval; +} + +/** + * This function prepares the core features descriptors and copies its + * raw representation into the buffer . + * + * The buffer structure is as follows: + * all_features_header (8 bytes) + * features_#1 (8 bytes + feature name string length) + * features_#2 (8 bytes + feature name string length) + * ..... + * features_#n - where n=the total count of feature descriptors + */ +static int cfi_core_features_buf(uint8_t * buf, uint16_t buflen) +{ + cfi_feature_desc_header_t *prop_hdr = prop_descs; + cfi_feature_desc_header_t *prop; + cfi_all_features_header_t *all_props_hdr = &all_props_desc_header; + cfi_all_features_header_t *tmp; + uint8_t *tmpbuf = buf; + const uint8_t *pname = NULL; + int i, j, namelen = 0, totlen; + + /* Prepare and copy the core features into the buffer */ + CFI_INFO("%s:\n", __func__); + + tmp = (cfi_all_features_header_t *) tmpbuf; + *tmp = *all_props_hdr; + tmpbuf += CFI_ALL_FEATURES_HDR_LEN; + + j = sizeof(prop_descs) / sizeof(cfi_all_features_header_t); + for (i = 0; i < j; i++, prop_hdr++) { + pname = get_prop_name(prop_hdr->wFeatureID, &namelen); + prop = (cfi_feature_desc_header_t *) tmpbuf; + *prop = *prop_hdr; + + prop->bNameLen = namelen; + prop->wLength = + DWC_CONSTANT_CPU_TO_LE16(CFI_FEATURE_DESC_HDR_LEN + + namelen); + + tmpbuf += CFI_FEATURE_DESC_HDR_LEN; + dwc_memcpy(tmpbuf, pname, namelen); + tmpbuf += namelen; + } + + totlen = tmpbuf - buf; + + if (totlen > 0) { + tmp = (cfi_all_features_header_t *) buf; + tmp->wTotalLen = DWC_CONSTANT_CPU_TO_LE16(totlen); + } + + return totlen; +} + +/** + * This function releases all the dynamic memory in the CFI object. + */ +static void cfi_release(cfiobject_t * cfiobj) +{ + cfi_ep_t *cfiep; + dwc_list_link_t *tmp; + + CFI_INFO("%s\n", __func__); + + if (cfiobj->buf_in.buf) { + dwc_dma_free(CFI_IN_BUF_LEN, cfiobj->buf_in.buf, + cfiobj->buf_in.addr); + cfiobj->buf_in.buf = NULL; + } + + if (cfiobj->buf_out.buf) { + dwc_dma_free(CFI_OUT_BUF_LEN, cfiobj->buf_out.buf, + cfiobj->buf_out.addr); + cfiobj->buf_out.buf = NULL; + } + + /* Free the Buffer Setup values for each EP */ + //list_for_each_entry(cfiep, &cfiobj->active_eps, lh) { + DWC_LIST_FOREACH(tmp, &cfiobj->active_eps) { + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh); + cfi_free_ep_bs_dyn_data(cfiep); + } +} + +/** + * This function frees the dynamically allocated EP buffer setup data. + */ +static void cfi_free_ep_bs_dyn_data(cfi_ep_t * cfiep) +{ + if (cfiep->bm_sg) { + dwc_free(cfiep->bm_sg); + cfiep->bm_sg = NULL; + } + + if (cfiep->bm_align) { + dwc_free(cfiep->bm_align); + cfiep->bm_align = NULL; + } + + if (cfiep->bm_concat) { + if (NULL != cfiep->bm_concat->wTxBytes) { + dwc_free(cfiep->bm_concat->wTxBytes); + cfiep->bm_concat->wTxBytes = NULL; + } + dwc_free(cfiep->bm_concat); + cfiep->bm_concat = NULL; + } +} + +/** + * This function initializes the default values of the features + * for a specific endpoint and should be called only once when + * the EP is enabled first time. + */ +static int cfi_ep_init_defaults(struct dwc_otg_pcd *pcd, cfi_ep_t * cfiep) +{ + int retval = 0; + + cfiep->bm_sg = dwc_alloc(sizeof(ddma_sg_buffer_setup_t)); + if (NULL == cfiep->bm_sg) { + CFI_INFO("Failed to allocate memory for SG feature value\n"); + return -DWC_E_NO_MEMORY; + } + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t)); + + /* For the Concatenation feature's default value we do not allocate + * memory for the wTxBytes field - it will be done in the set_feature_value + * request handler. + */ + cfiep->bm_concat = dwc_alloc(sizeof(ddma_concat_buffer_setup_t)); + if (NULL == cfiep->bm_concat) { + CFI_INFO + ("Failed to allocate memory for CONCATENATION feature value\n"); + dwc_free(cfiep->bm_sg); + return -DWC_E_NO_MEMORY; + } + dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t)); + + cfiep->bm_align = dwc_alloc(sizeof(ddma_align_buffer_setup_t)); + if (NULL == cfiep->bm_align) { + CFI_INFO + ("Failed to allocate memory for Alignment feature value\n"); + dwc_free(cfiep->bm_sg); + dwc_free(cfiep->bm_concat); + return -DWC_E_NO_MEMORY; + } + dwc_memset(cfiep->bm_align, 0, sizeof(ddma_align_buffer_setup_t)); + + return retval; +} + +/** + * The callback function that notifies the CFI on the activation of + * an endpoint in the PCD. The following steps are done in this function: + * + * Create a dynamically allocated cfi_ep_t object (a CFI wrapper to the PCD's + * active endpoint) + * Create MAX_DMA_DESCS_PER_EP count DMA Descriptors for the EP + * Set the Buffer Mode to standard + * Initialize the default values for all EP modes (SG, Circular, Concat, Align) + * Add the cfi_ep_t object to the list of active endpoints in the CFI object + */ +static int cfi_ep_enable(struct cfiobject *cfi, struct dwc_otg_pcd *pcd, + struct dwc_otg_pcd_ep *ep) +{ + cfi_ep_t *cfiep; + int retval = -DWC_E_NOT_SUPPORTED; + + CFI_INFO("%s: epname=%s; epnum=0x%02x\n", __func__, + "EP_" /*ep->ep.name */ , ep->desc->bEndpointAddress); + /* MAS - Check whether this endpoint already is in the list */ + cfiep = get_cfi_ep_by_pcd_ep(cfi, ep); + + if (NULL == cfiep) { + /* Allocate a cfi_ep_t object */ + cfiep = dwc_alloc(sizeof(cfi_ep_t)); + if (NULL == cfiep) { + CFI_INFO + ("Unable to allocate memory for in function %s\n", + __func__); + return -DWC_E_NO_MEMORY; + } + dwc_memset(cfiep, 0, sizeof(cfi_ep_t)); + + /* Save the dwc_otg_pcd_ep pointer in the cfiep object */ + cfiep->ep = ep; + + /* Allocate the DMA Descriptors chain of MAX_DMA_DESCS_PER_EP count */ + ep->dwc_ep.descs = + dwc_dma_alloc(MAX_DMA_DESCS_PER_EP * + sizeof(dwc_otg_dma_desc_t), + &ep->dwc_ep.descs_dma_addr); + + if (NULL == ep->dwc_ep.descs) { + dwc_free(cfiep); + return -DWC_E_NO_MEMORY; + } + + DWC_LIST_INIT(&cfiep->lh); + + /* Set the buffer mode to BM_STANDARD. It will be modified + * when building descriptors for a specific buffer mode */ + ep->dwc_ep.buff_mode = BM_STANDARD; + + /* Create and initialize the default values for this EP's Buffer modes */ + if ((retval = cfi_ep_init_defaults(pcd, cfiep)) < 0) + return retval; + + /* Add the cfi_ep_t object to the CFI object's list of active endpoints */ + DWC_LIST_INSERT_TAIL(&cfi->active_eps, &cfiep->lh); + retval = 0; + } else { /* The sought EP already is in the list */ + CFI_INFO("%s: The sought EP already is in the list\n", + __func__); + } + + return retval; +} + +/** + * This function is called when the data stage of a 3-stage Control Write request + * is complete. + * + */ +static int cfi_ctrl_write_complete(struct cfiobject *cfi, + struct dwc_otg_pcd *pcd) +{ + uint32_t addr, reg_value; + uint16_t wIndex, wValue; + uint8_t bRequest; + uint8_t *buf = cfi->buf_out.buf; + //struct usb_ctrlrequest *ctrl_req = &cfi->ctrl_req_saved; + struct cfi_usb_ctrlrequest *ctrl_req = &cfi->ctrl_req; + int retval = -DWC_E_NOT_SUPPORTED; + + CFI_INFO("%s\n", __func__); + + bRequest = ctrl_req->bRequest; + wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex); + wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue); + + /* + * Save the pointer to the data stage in the ctrl_req's field. + * The request should be already saved in the command stage by now. + */ + ctrl_req->data = cfi->buf_out.buf; + cfi->need_status_in_complete = 0; + cfi->need_gadget_att = 0; + + switch (bRequest) { + case VEN_CORE_WRITE_REGISTER: + /* The buffer contains raw data of the new value for the register */ + reg_value = *((uint32_t *) buf); + if (wValue == 0) { + addr = 0; + //addr = (uint32_t) pcd->otg_dev->base; + addr += wIndex; + } else { + addr = (wValue << 16) | wIndex; + } + + //writel(reg_value, addr); + + retval = 0; + cfi->need_status_in_complete = 1; + break; + + case VEN_CORE_SET_FEATURE: + /* The buffer contains raw data of the new value of the feature */ + retval = cfi_set_feature_value(pcd); + if (retval < 0) + return retval; + + cfi->need_status_in_complete = 1; + break; + + default: + break; + } + + return retval; +} + +/** + * This function builds the DMA descriptors for the SG buffer mode. + */ +static void cfi_build_sg_descs(struct cfiobject *cfi, cfi_ep_t * cfiep, + dwc_otg_pcd_request_t * req) +{ + struct dwc_otg_pcd_ep *ep = cfiep->ep; + ddma_sg_buffer_setup_t *sgval = cfiep->bm_sg; + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs; + struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs; + dma_addr_t buff_addr = req->dma; + int i; + uint32_t txsize, off; + + txsize = sgval->wSize; + off = sgval->bOffset; + +// CFI_INFO("%s: %s TXSIZE=0x%08x; OFFSET=0x%08x\n", +// __func__, cfiep->ep->ep.name, txsize, off); + + for (i = 0; i < sgval->bCount; i++) { + desc->status.b.bs = BS_HOST_BUSY; + desc->buf = buff_addr; + desc->status.b.l = 0; + desc->status.b.ioc = 0; + desc->status.b.sp = 0; + desc->status.b.bytes = txsize; + desc->status.b.bs = BS_HOST_READY; + + /* Set the next address of the buffer */ + buff_addr += txsize + off; + desc_last = desc; + desc++; + } + + /* Set the last, ioc and sp bits on the Last DMA Descriptor */ + desc_last->status.b.l = 1; + desc_last->status.b.ioc = 1; + desc_last->status.b.sp = ep->dwc_ep.sent_zlp; + /* Save the last DMA descriptor pointer */ + cfiep->dma_desc_last = desc_last; + cfiep->desc_count = sgval->bCount; +} + +/** + * This function builds the DMA descriptors for the Concatenation buffer mode. + */ +static void cfi_build_concat_descs(struct cfiobject *cfi, cfi_ep_t * cfiep, + dwc_otg_pcd_request_t * req) +{ + struct dwc_otg_pcd_ep *ep = cfiep->ep; + ddma_concat_buffer_setup_t *concatval = cfiep->bm_concat; + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs; + struct dwc_otg_dma_desc *desc_last = cfiep->ep->dwc_ep.descs; + dma_addr_t buff_addr = req->dma; + int i; + uint16_t *txsize; + + txsize = concatval->wTxBytes; + + for (i = 0; i < concatval->hdr.bDescCount; i++) { + desc->buf = buff_addr; + desc->status.b.bs = BS_HOST_BUSY; + desc->status.b.l = 0; + desc->status.b.ioc = 0; + desc->status.b.sp = 0; + desc->status.b.bytes = *txsize; + desc->status.b.bs = BS_HOST_READY; + + txsize++; + /* Set the next address of the buffer */ + buff_addr += UGETW(ep->desc->wMaxPacketSize); + desc_last = desc; + desc++; + } + + /* Set the last, ioc and sp bits on the Last DMA Descriptor */ + desc_last->status.b.l = 1; + desc_last->status.b.ioc = 1; + desc_last->status.b.sp = ep->dwc_ep.sent_zlp; + cfiep->dma_desc_last = desc_last; + cfiep->desc_count = concatval->hdr.bDescCount; +} + +/** + * This function builds the DMA descriptors for the Circular buffer mode + */ +static void cfi_build_circ_descs(struct cfiobject *cfi, cfi_ep_t * cfiep, + dwc_otg_pcd_request_t * req) +{ + /* @todo: MAS - add implementation when this feature needs to be tested */ +} + +/** + * This function builds the DMA descriptors for the Alignment buffer mode + */ +static void cfi_build_align_descs(struct cfiobject *cfi, cfi_ep_t * cfiep, + dwc_otg_pcd_request_t * req) +{ + struct dwc_otg_pcd_ep *ep = cfiep->ep; + ddma_align_buffer_setup_t *alignval = cfiep->bm_align; + struct dwc_otg_dma_desc *desc = cfiep->ep->dwc_ep.descs; + dma_addr_t buff_addr = req->dma; + + desc->status.b.bs = BS_HOST_BUSY; + desc->status.b.l = 1; + desc->status.b.ioc = 1; + desc->status.b.sp = ep->dwc_ep.sent_zlp; + desc->status.b.bytes = req->length; + /* Adjust the buffer alignment */ + desc->buf = (buff_addr + alignval->bAlign); + desc->status.b.bs = BS_HOST_READY; + cfiep->dma_desc_last = desc; + cfiep->desc_count = 1; +} + +/** + * This function builds the DMA descriptors chain for different modes of the + * buffer setup of an endpoint. + */ +static void cfi_build_descriptors(struct cfiobject *cfi, + struct dwc_otg_pcd *pcd, + struct dwc_otg_pcd_ep *ep, + dwc_otg_pcd_request_t * req) +{ + cfi_ep_t *cfiep; + + /* Get the cfiep by the dwc_otg_pcd_ep */ + cfiep = get_cfi_ep_by_pcd_ep(cfi, ep); + if (NULL == cfiep) { + CFI_INFO("%s: Unable to find a matching active endpoint\n", + __func__); + return; + } + + cfiep->xfer_len = req->length; + + /* Iterate through all the DMA descriptors */ + switch (cfiep->ep->dwc_ep.buff_mode) { + case BM_SG: + cfi_build_sg_descs(cfi, cfiep, req); + break; + + case BM_CONCAT: + cfi_build_concat_descs(cfi, cfiep, req); + break; + + case BM_CIRCULAR: + cfi_build_circ_descs(cfi, cfiep, req); + break; + + case BM_ALIGN: + cfi_build_align_descs(cfi, cfiep, req); + break; + + default: + break; + } +} + +/** + * Allocate DMA buffer for different Buffer modes. + */ +static void *cfi_ep_alloc_buf(struct cfiobject *cfi, struct dwc_otg_pcd *pcd, + struct dwc_otg_pcd_ep *ep, dma_addr_t * dma, + unsigned size, gfp_t flags) +{ + return dwc_dma_alloc(size, dma); +} + +/** + * This function initializes the CFI object. + */ +int init_cfi(cfiobject_t * cfiobj) +{ + CFI_INFO("%s\n", __func__); + + /* Allocate a buffer for IN XFERs */ + cfiobj->buf_in.buf = + dwc_dma_alloc(CFI_IN_BUF_LEN, &cfiobj->buf_in.addr); + if (NULL == cfiobj->buf_in.buf) { + CFI_INFO("Unable to allocate buffer for INs\n"); + return -DWC_E_NO_MEMORY; + } + + /* Allocate a buffer for OUT XFERs */ + cfiobj->buf_out.buf = + dwc_dma_alloc(CFI_OUT_BUF_LEN, &cfiobj->buf_out.addr); + if (NULL == cfiobj->buf_out.buf) { + CFI_INFO("Unable to allocate buffer for OUT\n"); + return -DWC_E_NO_MEMORY; + } + + /* Initialize the callback function pointers */ + cfiobj->ops.release = cfi_release; + cfiobj->ops.ep_enable = cfi_ep_enable; + cfiobj->ops.ctrl_write_complete = cfi_ctrl_write_complete; + cfiobj->ops.build_descriptors = cfi_build_descriptors; + cfiobj->ops.ep_alloc_buf = cfi_ep_alloc_buf; + + /* Initialize the list of active endpoints in the CFI object */ + DWC_LIST_INIT(&cfiobj->active_eps); + + return 0; +} + +/** + * This function reads the required feature's current value into the buffer + * + * @retval: Returns negative as error, or the data length of the feature + */ +static int cfi_get_feature_value(uint8_t * buf, uint16_t buflen, + struct dwc_otg_pcd *pcd, + struct cfi_usb_ctrlrequest *ctrl_req) +{ + int retval = -DWC_E_NOT_SUPPORTED; + struct dwc_otg_core_if *coreif = GET_CORE_IF(pcd); + uint16_t dfifo, rxfifo, txfifo; + + switch (ctrl_req->wIndex) { + /* Whether the DDMA is enabled or not */ + case FT_ID_DMA_MODE: + *buf = (coreif->dma_enable && coreif->dma_desc_enable) ? 1 : 0; + retval = 1; + break; + + case FT_ID_DMA_BUFFER_SETUP: + retval = cfi_ep_get_sg_val(buf, pcd, ctrl_req); + break; + + case FT_ID_DMA_BUFF_ALIGN: + retval = cfi_ep_get_align_val(buf, pcd, ctrl_req); + break; + + case FT_ID_DMA_CONCAT_SETUP: + retval = cfi_ep_get_concat_val(buf, pcd, ctrl_req); + break; + + case FT_ID_DMA_CIRCULAR: + CFI_INFO("GetFeature value (FT_ID_DMA_CIRCULAR)\n"); + break; + + case FT_ID_THRESHOLD_SETUP: + CFI_INFO("GetFeature value (FT_ID_THRESHOLD_SETUP)\n"); + break; + + case FT_ID_DFIFO_DEPTH: + dfifo = get_dfifo_size(coreif); + *((uint16_t *) buf) = dfifo; + retval = sizeof(uint16_t); + break; + + case FT_ID_TX_FIFO_DEPTH: + retval = get_txfifo_size(pcd, ctrl_req->wValue); + if (retval >= 0) { + txfifo = retval; + *((uint16_t *) buf) = txfifo; + retval = sizeof(uint16_t); + } + break; + + case FT_ID_RX_FIFO_DEPTH: + retval = get_rxfifo_size(coreif, ctrl_req->wValue); + if (retval >= 0) { + rxfifo = retval; + *((uint16_t *) buf) = rxfifo; + retval = sizeof(uint16_t); + } + break; + } + + return retval; +} + +/** + * This function resets the SG for the specified EP to its default value + */ +static int cfi_reset_sg_val(cfi_ep_t * cfiep) +{ + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t)); + return 0; +} + +/** + * This function resets the Alignment for the specified EP to its default value + */ +static int cfi_reset_align_val(cfi_ep_t * cfiep) +{ + dwc_memset(cfiep->bm_sg, 0, sizeof(ddma_sg_buffer_setup_t)); + return 0; +} + +/** + * This function resets the Concatenation for the specified EP to its default value + * This function will also set the value of the wTxBytes field to NULL after + * freeing the memory previously allocated for this field. + */ +static int cfi_reset_concat_val(cfi_ep_t * cfiep) +{ + /* First we need to free the wTxBytes field */ + if (cfiep->bm_concat->wTxBytes) { + dwc_free(cfiep->bm_concat->wTxBytes); + cfiep->bm_concat->wTxBytes = NULL; + } + + dwc_memset(cfiep->bm_concat, 0, sizeof(ddma_concat_buffer_setup_t)); + return 0; +} + +/** + * This function resets all the buffer setups of the specified endpoint + */ +static int cfi_ep_reset_all_setup_vals(cfi_ep_t * cfiep) +{ + cfi_reset_sg_val(cfiep); + cfi_reset_align_val(cfiep); + cfi_reset_concat_val(cfiep); + return 0; +} + +static int cfi_handle_reset_fifo_val(struct dwc_otg_pcd *pcd, uint8_t ep_addr, + uint8_t rx_rst, uint8_t tx_rst) +{ + int retval = -DWC_E_INVALID; + uint16_t tx_siz[15]; + uint16_t rx_siz = 0; + dwc_otg_pcd_ep_t *ep = NULL; + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params; + + if (rx_rst) { + rx_siz = params->dev_rx_fifo_size; + params->dev_rx_fifo_size = GET_CORE_IF(pcd)->init_rxfsiz; + } + + if (tx_rst) { + if (ep_addr == 0) { + int i; + + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) { + tx_siz[i] = + core_if->core_params->dev_tx_fifo_size[i]; + core_if->core_params->dev_tx_fifo_size[i] = + core_if->init_txfsiz[i]; + } + } else { + + ep = get_ep_by_addr(pcd, ep_addr); + + if (NULL == ep) { + CFI_INFO + ("%s: Unable to get the endpoint addr=0x%02x\n", + __func__, ep_addr); + return -DWC_E_INVALID; + } + + tx_siz[0] = + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - + 1]; + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = + GET_CORE_IF(pcd)->init_txfsiz[ep->dwc_ep. + tx_fifo_num - 1]; + } + } + + if (resize_fifos(GET_CORE_IF(pcd))) { + retval = 0; + } else { + CFI_INFO + ("%s: Error resetting the feature Reset All(FIFO size)\n", + __func__); + if (rx_rst) { + params->dev_rx_fifo_size = rx_siz; + } + + if (tx_rst) { + if (ep_addr == 0) { + int i; + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; + i++) { + core_if->core_params-> + dev_tx_fifo_size[i] = tx_siz[i]; + } + } else { + params->dev_tx_fifo_size[ep->dwc_ep. + tx_fifo_num - 1] = + tx_siz[0]; + } + } + retval = -DWC_E_INVALID; + } + return retval; +} + +static int cfi_handle_reset_all(struct dwc_otg_pcd *pcd, uint8_t addr) +{ + int retval = 0; + cfi_ep_t *cfiep; + cfiobject_t *cfi = pcd->cfi; + dwc_list_link_t *tmp; + + retval = cfi_handle_reset_fifo_val(pcd, addr, 1, 1); + if (retval < 0) { + return retval; + } + + /* If the EP address is known then reset the features for only that EP */ + if (addr) { + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr); + if (NULL == cfiep) { + CFI_INFO("%s: Error getting the EP address 0x%02x\n", + __func__, addr); + return -DWC_E_INVALID; + } + retval = cfi_ep_reset_all_setup_vals(cfiep); + cfiep->ep->dwc_ep.buff_mode = BM_STANDARD; + } + /* Otherwise (wValue == 0), reset all features of all EP's */ + else { + /* Traverse all the active EP's and reset the feature(s) value(s) */ + //list_for_each_entry(cfiep, &cfi->active_eps, lh) { + DWC_LIST_FOREACH(tmp, &cfi->active_eps) { + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh); + retval = cfi_ep_reset_all_setup_vals(cfiep); + cfiep->ep->dwc_ep.buff_mode = BM_STANDARD; + if (retval < 0) { + CFI_INFO + ("%s: Error resetting the feature Reset All\n", + __func__); + return retval; + } + } + } + return retval; +} + +static int cfi_handle_reset_dma_buff_setup(struct dwc_otg_pcd *pcd, + uint8_t addr) +{ + int retval = 0; + cfi_ep_t *cfiep; + cfiobject_t *cfi = pcd->cfi; + dwc_list_link_t *tmp; + + /* If the EP address is known then reset the features for only that EP */ + if (addr) { + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr); + if (NULL == cfiep) { + CFI_INFO("%s: Error getting the EP address 0x%02x\n", + __func__, addr); + return -DWC_E_INVALID; + } + retval = cfi_reset_sg_val(cfiep); + } + /* Otherwise (wValue == 0), reset all features of all EP's */ + else { + /* Traverse all the active EP's and reset the feature(s) value(s) */ + //list_for_each_entry(cfiep, &cfi->active_eps, lh) { + DWC_LIST_FOREACH(tmp, &cfi->active_eps) { + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh); + retval = cfi_reset_sg_val(cfiep); + if (retval < 0) { + CFI_INFO + ("%s: Error resetting the feature Buffer Setup\n", + __func__); + return retval; + } + } + } + return retval; +} + +static int cfi_handle_reset_concat_val(struct dwc_otg_pcd *pcd, uint8_t addr) +{ + int retval = 0; + cfi_ep_t *cfiep; + cfiobject_t *cfi = pcd->cfi; + dwc_list_link_t *tmp; + + /* If the EP address is known then reset the features for only that EP */ + if (addr) { + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr); + if (NULL == cfiep) { + CFI_INFO("%s: Error getting the EP address 0x%02x\n", + __func__, addr); + return -DWC_E_INVALID; + } + retval = cfi_reset_concat_val(cfiep); + } + /* Otherwise (wValue == 0), reset all features of all EP's */ + else { + /* Traverse all the active EP's and reset the feature(s) value(s) */ + //list_for_each_entry(cfiep, &cfi->active_eps, lh) { + DWC_LIST_FOREACH(tmp, &cfi->active_eps) { + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh); + retval = cfi_reset_concat_val(cfiep); + if (retval < 0) { + CFI_INFO + ("%s: Error resetting the feature Concatenation Value\n", + __func__); + return retval; + } + } + } + return retval; +} + +static int cfi_handle_reset_align_val(struct dwc_otg_pcd *pcd, uint8_t addr) +{ + int retval = 0; + cfi_ep_t *cfiep; + cfiobject_t *cfi = pcd->cfi; + dwc_list_link_t *tmp; + + /* If the EP address is known then reset the features for only that EP */ + if (addr) { + cfiep = get_cfi_ep_by_addr(pcd->cfi, addr); + if (NULL == cfiep) { + CFI_INFO("%s: Error getting the EP address 0x%02x\n", + __func__, addr); + return -DWC_E_INVALID; + } + retval = cfi_reset_align_val(cfiep); + } + /* Otherwise (wValue == 0), reset all features of all EP's */ + else { + /* Traverse all the active EP's and reset the feature(s) value(s) */ + //list_for_each_entry(cfiep, &cfi->active_eps, lh) { + DWC_LIST_FOREACH(tmp, &cfi->active_eps) { + cfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh); + retval = cfi_reset_align_val(cfiep); + if (retval < 0) { + CFI_INFO + ("%s: Error resetting the feature Aliignment Value\n", + __func__); + return retval; + } + } + } + return retval; + +} + +static int cfi_preproc_reset(struct dwc_otg_pcd *pcd, + struct cfi_usb_ctrlrequest *req) +{ + int retval = 0; + + switch (req->wIndex) { + case 0: + /* Reset all features */ + retval = cfi_handle_reset_all(pcd, req->wValue & 0xff); + break; + + case FT_ID_DMA_BUFFER_SETUP: + /* Reset the SG buffer setup */ + retval = + cfi_handle_reset_dma_buff_setup(pcd, req->wValue & 0xff); + break; + + case FT_ID_DMA_CONCAT_SETUP: + /* Reset the Concatenation buffer setup */ + retval = cfi_handle_reset_concat_val(pcd, req->wValue & 0xff); + break; + + case FT_ID_DMA_BUFF_ALIGN: + /* Reset the Alignment buffer setup */ + retval = cfi_handle_reset_align_val(pcd, req->wValue & 0xff); + break; + + case FT_ID_TX_FIFO_DEPTH: + retval = + cfi_handle_reset_fifo_val(pcd, req->wValue & 0xff, 0, 1); + pcd->cfi->need_gadget_att = 0; + break; + + case FT_ID_RX_FIFO_DEPTH: + retval = cfi_handle_reset_fifo_val(pcd, 0, 1, 0); + pcd->cfi->need_gadget_att = 0; + break; + default: + break; + } + return retval; +} + +/** + * This function sets a new value for the SG buffer setup. + */ +static int cfi_ep_set_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd) +{ + uint8_t inaddr, outaddr; + cfi_ep_t *epin, *epout; + ddma_sg_buffer_setup_t *psgval; + uint32_t desccount, size; + + CFI_INFO("%s\n", __func__); + + psgval = (ddma_sg_buffer_setup_t *) buf; + desccount = (uint32_t) psgval->bCount; + size = (uint32_t) psgval->wSize; + + /* Check the DMA descriptor count */ + if ((desccount > MAX_DMA_DESCS_PER_EP) || (desccount == 0)) { + CFI_INFO + ("%s: The count of DMA Descriptors should be between 1 and %d\n", + __func__, MAX_DMA_DESCS_PER_EP); + return -DWC_E_INVALID; + } + + /* Check the DMA descriptor count */ + + if (size == 0) { + + CFI_INFO("%s: The transfer size should be at least 1 byte\n", + __func__); + + return -DWC_E_INVALID; + + } + + inaddr = psgval->bInEndpointAddress; + outaddr = psgval->bOutEndpointAddress; + + epin = get_cfi_ep_by_addr(pcd->cfi, inaddr); + epout = get_cfi_ep_by_addr(pcd->cfi, outaddr); + + if (NULL == epin || NULL == epout) { + CFI_INFO + ("%s: Unable to get the endpoints inaddr=0x%02x outaddr=0x%02x\n", + __func__, inaddr, outaddr); + return -DWC_E_INVALID; + } + + epin->ep->dwc_ep.buff_mode = BM_SG; + dwc_memcpy(epin->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t)); + + epout->ep->dwc_ep.buff_mode = BM_SG; + dwc_memcpy(epout->bm_sg, psgval, sizeof(ddma_sg_buffer_setup_t)); + + return 0; +} + +/** + * This function sets a new value for the buffer Alignment setup. + */ +static int cfi_ep_set_alignment_val(uint8_t * buf, struct dwc_otg_pcd *pcd) +{ + cfi_ep_t *ep; + uint8_t addr; + ddma_align_buffer_setup_t *palignval; + + palignval = (ddma_align_buffer_setup_t *) buf; + addr = palignval->bEndpointAddress; + + ep = get_cfi_ep_by_addr(pcd->cfi, addr); + + if (NULL == ep) { + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n", + __func__, addr); + return -DWC_E_INVALID; + } + + ep->ep->dwc_ep.buff_mode = BM_ALIGN; + dwc_memcpy(ep->bm_align, palignval, sizeof(ddma_align_buffer_setup_t)); + + return 0; +} + +/** + * This function sets a new value for the Concatenation buffer setup. + */ +static int cfi_ep_set_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd) +{ + uint8_t addr; + cfi_ep_t *ep; + struct _ddma_concat_buffer_setup_hdr *pConcatValHdr; + uint16_t *pVals; + uint32_t desccount; + int i; + uint16_t mps; + + pConcatValHdr = (struct _ddma_concat_buffer_setup_hdr *)buf; + desccount = (uint32_t) pConcatValHdr->bDescCount; + pVals = (uint16_t *) (buf + BS_CONCAT_VAL_HDR_LEN); + + /* Check the DMA descriptor count */ + if (desccount > MAX_DMA_DESCS_PER_EP) { + CFI_INFO("%s: Maximum DMA Descriptor count should be %d\n", + __func__, MAX_DMA_DESCS_PER_EP); + return -DWC_E_INVALID; + } + + addr = pConcatValHdr->bEndpointAddress; + ep = get_cfi_ep_by_addr(pcd->cfi, addr); + if (NULL == ep) { + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n", + __func__, addr); + return -DWC_E_INVALID; + } + + mps = UGETW(ep->ep->desc->wMaxPacketSize); + +#if 0 + for (i = 0; i < desccount; i++) { + CFI_INFO("%s: wTxSize[%d]=0x%04x\n", __func__, i, pVals[i]); + } + CFI_INFO("%s: epname=%s; mps=%d\n", __func__, ep->ep->ep.name, mps); +#endif + + /* Check the wTxSizes to be less than or equal to the mps */ + for (i = 0; i < desccount; i++) { + if (pVals[i] > mps) { + CFI_INFO + ("%s: ERROR - the wTxSize[%d] should be <= MPS (wTxSize=%d)\n", + __func__, i, pVals[i]); + return -DWC_E_INVALID; + } + } + + ep->ep->dwc_ep.buff_mode = BM_CONCAT; + dwc_memcpy(ep->bm_concat, pConcatValHdr, BS_CONCAT_VAL_HDR_LEN); + + /* Free the previously allocated storage for the wTxBytes */ + if (ep->bm_concat->wTxBytes) { + dwc_free(ep->bm_concat->wTxBytes); + } + + /* Allocate a new storage for the wTxBytes field */ + ep->bm_concat->wTxBytes = + dwc_alloc(sizeof(uint16_t) * pConcatValHdr->bDescCount); + if (NULL == ep->bm_concat->wTxBytes) { + CFI_INFO("%s: Unable to allocate memory\n", __func__); + return -DWC_E_NO_MEMORY; + } + + /* Copy the new values into the wTxBytes filed */ + dwc_memcpy(ep->bm_concat->wTxBytes, buf + BS_CONCAT_VAL_HDR_LEN, + sizeof(uint16_t) * pConcatValHdr->bDescCount); + + return 0; +} + +/** + * This function calculates the total of all FIFO sizes + * + * @param core_if Programming view of DWC_otg controller + * + * @return The total of data FIFO sizes. + * + */ +static uint16_t get_dfifo_size(dwc_otg_core_if_t * core_if) +{ + dwc_otg_core_params_t *params = core_if->core_params; + uint16_t dfifo_total = 0; + int i; + + /* The shared RxFIFO size */ + dfifo_total = + params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size; + + /* Add up each TxFIFO size to the total */ + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) { + dfifo_total += params->dev_tx_fifo_size[i]; + } + + return dfifo_total; +} + +/** + * This function returns Rx FIFO size + * + * @param core_if Programming view of DWC_otg controller + * + * @return The total of data FIFO sizes. + * + */ +static int32_t get_rxfifo_size(dwc_otg_core_if_t * core_if, uint16_t wValue) +{ + switch (wValue >> 8) { + case 0: + return (core_if->pwron_rxfsiz < + 32768) ? core_if->pwron_rxfsiz : 32768; + break; + case 1: + return core_if->core_params->dev_rx_fifo_size; + break; + default: + return -DWC_E_INVALID; + break; + } +} + +/** + * This function returns Tx FIFO size for IN EP + * + * @param core_if Programming view of DWC_otg controller + * + * @return The total of data FIFO sizes. + * + */ +static int32_t get_txfifo_size(struct dwc_otg_pcd *pcd, uint16_t wValue) +{ + dwc_otg_pcd_ep_t *ep; + + ep = get_ep_by_addr(pcd, wValue & 0xff); + + if (NULL == ep) { + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n", + __func__, wValue & 0xff); + return -DWC_E_INVALID; + } + + if (!ep->dwc_ep.is_in) { + CFI_INFO + ("%s: No Tx FIFO assingned to the Out endpoint addr=0x%02x\n", + __func__, wValue & 0xff); + return -DWC_E_INVALID; + } + + switch (wValue >> 8) { + case 0: + return (GET_CORE_IF(pcd)-> + pwron_txfsiz[ep->dwc_ep.tx_fifo_num - 1] < + 768) ? GET_CORE_IF(pcd)->pwron_txfsiz[ep->dwc_ep. + tx_fifo_num - + 1] : 32768; + break; + case 1: + return GET_CORE_IF(pcd)->core_params->dev_tx_fifo_size[ep-> + dwc_ep. + num - 1]; + break; + default: + return -DWC_E_INVALID; + break; + } +} + +/** + * This function checks if the submitted combination of + * device mode FIFO sizes is possible or not. + * + * @param core_if Programming view of DWC_otg controller + * + * @return 1 if possible, 0 otherwise. + * + */ +static uint8_t check_fifo_sizes(dwc_otg_core_if_t * core_if) +{ + uint16_t dfifo_actual = 0; + dwc_otg_core_params_t *params = core_if->core_params; + uint16_t start_addr = 0; + int i; + + dfifo_actual = + params->dev_rx_fifo_size + params->dev_nperio_tx_fifo_size; + + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) { + dfifo_actual += params->dev_tx_fifo_size[i]; + } + + if (dfifo_actual > core_if->total_fifo_size) { + return 0; + } + + if (params->dev_rx_fifo_size > 32768 || params->dev_rx_fifo_size < 16) + return 0; + + if (params->dev_nperio_tx_fifo_size > 32768 + || params->dev_nperio_tx_fifo_size < 16) + return 0; + + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) { + + if (params->dev_tx_fifo_size[i] > 768 + || params->dev_tx_fifo_size[i] < 4) + return 0; + } + + if (params->dev_rx_fifo_size > core_if->pwron_rxfsiz) + return 0; + start_addr = params->dev_rx_fifo_size; + + if (params->dev_nperio_tx_fifo_size > core_if->pwron_gnptxfsiz) + return 0; + start_addr += params->dev_nperio_tx_fifo_size; + + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) { + + if (params->dev_tx_fifo_size[i] > core_if->pwron_txfsiz[i]) + return 0; + start_addr += params->dev_tx_fifo_size[i]; + } + + return 1; +} + +/** + * This function resizes Device mode FIFOs + * + * @param core_if Programming view of DWC_otg controller + * + * @return 1 if successful, 0 otherwise + * + */ +static uint8_t resize_fifos(dwc_otg_core_if_t * core_if) +{ + int i = 0; + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; + dwc_otg_core_params_t *params = core_if->core_params; + uint32_t rx_fifo_size; + fifosize_data_t nptxfifosize; + fifosize_data_t txfifosize[15]; + + uint32_t rx_fsz_bak; + uint32_t nptxfsz_bak; + uint32_t txfsz_bak[15]; + + uint16_t start_address; + uint8_t retval = 1; + + if (!check_fifo_sizes(core_if)) { + return 0; + } + + /* Configure data FIFO sizes */ + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) { + rx_fsz_bak = dwc_read_reg32(&global_regs->grxfsiz); + rx_fifo_size = params->dev_rx_fifo_size; + dwc_write_reg32(&global_regs->grxfsiz, rx_fifo_size); + + /* + * Tx FIFOs These FIFOs are numbered from 1 to 15. + * Indexes of the FIFO size module parameters in the + * dev_tx_fifo_size array and the FIFO size registers in + * the dptxfsiz_dieptxf array run from 0 to 14. + */ + + /* Non-periodic Tx FIFO */ + nptxfsz_bak = dwc_read_reg32(&global_regs->gnptxfsiz); + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size; + start_address = params->dev_rx_fifo_size; + nptxfifosize.b.startaddr = start_address; + + dwc_write_reg32(&global_regs->gnptxfsiz, nptxfifosize.d32); + + start_address += nptxfifosize.b.depth; + + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) { + txfsz_bak[i] = + dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i]); + + txfifosize[i].b.depth = params->dev_tx_fifo_size[i]; + txfifosize[i].b.startaddr = start_address; + dwc_write_reg32(&global_regs->dptxfsiz_dieptxf[i], + txfifosize[i].d32); + + start_address += txfifosize[i].b.depth; + } + + /** Check if register values are set correctly */ + if (rx_fifo_size != dwc_read_reg32(&global_regs->grxfsiz)) { + retval = 0; + } + + if (nptxfifosize.d32 != dwc_read_reg32(&global_regs->gnptxfsiz)) { + retval = 0; + } + + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) { + if (txfifosize[i].d32 != + dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i])) { + retval = 0; + } + } + + /** If register values are not set correctly, reset old values */ + if (retval == 0) { + dwc_write_reg32(&global_regs->grxfsiz, rx_fsz_bak); + + /* Non-periodic Tx FIFO */ + dwc_write_reg32(&global_regs->gnptxfsiz, nptxfsz_bak); + + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) { + dwc_write_reg32(&global_regs-> + dptxfsiz_dieptxf[i], + txfsz_bak[i]); + } + } + } else { + return 0; + } + + /* Flush the FIFOs */ + dwc_otg_flush_tx_fifo(core_if, 0x10); /* all Tx FIFOs */ + dwc_otg_flush_rx_fifo(core_if); + + return retval; +} + +/** + * This function sets a new value for the buffer Alignment setup. + */ +static int cfi_ep_set_tx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd) +{ + int retval; + uint32_t fsiz; + uint16_t size; + uint16_t ep_addr; + dwc_otg_pcd_ep_t *ep; + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params; + tx_fifo_size_setup_t *ptxfifoval; + + ptxfifoval = (tx_fifo_size_setup_t *) buf; + ep_addr = ptxfifoval->bEndpointAddress; + size = ptxfifoval->wDepth; + + ep = get_ep_by_addr(pcd, ep_addr); + + CFI_INFO + ("%s: Set Tx FIFO size: endpoint addr=0x%02x, depth=%d, FIFO Num=%d\n", + __func__, ep_addr, size, ep->dwc_ep.tx_fifo_num); + + if (NULL == ep) { + CFI_INFO("%s: Unable to get the endpoint addr=0x%02x\n", + __func__, ep_addr); + return -DWC_E_INVALID; + } + + fsiz = params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1]; + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = size; + + if (resize_fifos(GET_CORE_IF(pcd))) { + retval = 0; + } else { + CFI_INFO + ("%s: Error setting the feature Tx FIFO Size for EP%d\n", + __func__, ep_addr); + params->dev_tx_fifo_size[ep->dwc_ep.tx_fifo_num - 1] = fsiz; + retval = -DWC_E_INVALID; + } + + return retval; +} + +/** + * This function sets a new value for the buffer Alignment setup. + */ +static int cfi_set_rx_fifo_val(uint8_t * buf, dwc_otg_pcd_t * pcd) +{ + int retval; + uint32_t fsiz; + uint16_t size; + dwc_otg_core_params_t *params = GET_CORE_IF(pcd)->core_params; + rx_fifo_size_setup_t *prxfifoval; + + prxfifoval = (rx_fifo_size_setup_t *) buf; + size = prxfifoval->wDepth; + + fsiz = params->dev_rx_fifo_size; + params->dev_rx_fifo_size = size; + + if (resize_fifos(GET_CORE_IF(pcd))) { + retval = 0; + } else { + CFI_INFO("%s: Error setting the feature Rx FIFO Size\n", + __func__); + params->dev_rx_fifo_size = fsiz; + retval = -DWC_E_INVALID; + } + + return retval; +} + +/** + * This function reads the SG of an EP's buffer setup into the buffer buf + */ +static int cfi_ep_get_sg_val(uint8_t * buf, struct dwc_otg_pcd *pcd, + struct cfi_usb_ctrlrequest *req) +{ + int retval = -DWC_E_INVALID; + uint8_t addr; + cfi_ep_t *ep; + + /* The Low Byte of the wValue contains a non-zero address of the endpoint */ + addr = req->wValue & 0xFF; + if (addr == 0) /* The address should be non-zero */ + return retval; + + ep = get_cfi_ep_by_addr(pcd->cfi, addr); + if (NULL == ep) { + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n", + __func__, addr); + return retval; + } + + dwc_memcpy(buf, ep->bm_sg, BS_SG_VAL_DESC_LEN); + retval = BS_SG_VAL_DESC_LEN; + return retval; +} + +/** + * This function reads the Concatenation value of an EP's buffer mode into + * the buffer buf + */ +static int cfi_ep_get_concat_val(uint8_t * buf, struct dwc_otg_pcd *pcd, + struct cfi_usb_ctrlrequest *req) +{ + int retval = -DWC_E_INVALID; + uint8_t addr; + cfi_ep_t *ep; + uint8_t desc_count; + + /* The Low Byte of the wValue contains a non-zero address of the endpoint */ + addr = req->wValue & 0xFF; + if (addr == 0) /* The address should be non-zero */ + return retval; + + ep = get_cfi_ep_by_addr(pcd->cfi, addr); + if (NULL == ep) { + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n", + __func__, addr); + return retval; + } + + /* Copy the header to the buffer */ + dwc_memcpy(buf, ep->bm_concat, BS_CONCAT_VAL_HDR_LEN); + /* Advance the buffer pointer by the header size */ + buf += BS_CONCAT_VAL_HDR_LEN; + + desc_count = ep->bm_concat->hdr.bDescCount; + /* Copy alll the wTxBytes to the buffer */ + dwc_memcpy(buf, ep->bm_concat->wTxBytes, sizeof(uid16_t) * desc_count); + + retval = BS_CONCAT_VAL_HDR_LEN + sizeof(uid16_t) * desc_count; + return retval; +} + +/** + * This function reads the buffer Alignment value of an EP's buffer mode into + * the buffer buf + * + * @return The total number of bytes copied to the buffer or negative error code. + */ +static int cfi_ep_get_align_val(uint8_t * buf, struct dwc_otg_pcd *pcd, + struct cfi_usb_ctrlrequest *req) +{ + int retval = -DWC_E_INVALID; + uint8_t addr; + cfi_ep_t *ep; + + /* The Low Byte of the wValue contains a non-zero address of the endpoint */ + addr = req->wValue & 0xFF; + if (addr == 0) /* The address should be non-zero */ + return retval; + + ep = get_cfi_ep_by_addr(pcd->cfi, addr); + if (NULL == ep) { + CFI_INFO("%s: Unable to get the endpoint address(0x%02x)\n", + __func__, addr); + return retval; + } + + dwc_memcpy(buf, ep->bm_align, BS_ALIGN_VAL_HDR_LEN); + retval = BS_ALIGN_VAL_HDR_LEN; + + return retval; +} + +/** + * This function sets a new value for the specified feature + * + * @param pcd A pointer to the PCD object + * + * @return 0 if successful, negative error code otherwise to stall the DCE. + */ +static int cfi_set_feature_value(struct dwc_otg_pcd *pcd) +{ + int retval = -DWC_E_NOT_SUPPORTED; + uint16_t wIndex, wValue; + uint8_t bRequest; + struct dwc_otg_core_if *coreif; + cfiobject_t *cfi = pcd->cfi; + struct cfi_usb_ctrlrequest *ctrl_req; + uint8_t *buf; + ctrl_req = &cfi->ctrl_req; + + buf = pcd->cfi->ctrl_req.data; + + coreif = GET_CORE_IF(pcd); + bRequest = ctrl_req->bRequest; + wIndex = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wIndex); + wValue = DWC_CONSTANT_CPU_TO_LE16(ctrl_req->wValue); + + /* See which feature is to be modified */ + switch (wIndex) { + case FT_ID_DMA_BUFFER_SETUP: + /* Modify the feature */ + if ((retval = cfi_ep_set_sg_val(buf, pcd)) < 0) + return retval; + + /* And send this request to the gadget */ + cfi->need_gadget_att = 1; + break; + + case FT_ID_DMA_BUFF_ALIGN: + if ((retval = cfi_ep_set_alignment_val(buf, pcd)) < 0) + return retval; + cfi->need_gadget_att = 1; + break; + + case FT_ID_DMA_CONCAT_SETUP: + /* Modify the feature */ + if ((retval = cfi_ep_set_concat_val(buf, pcd)) < 0) + return retval; + cfi->need_gadget_att = 1; + break; + + case FT_ID_DMA_CIRCULAR: + CFI_INFO("FT_ID_DMA_CIRCULAR\n"); + break; + + case FT_ID_THRESHOLD_SETUP: + CFI_INFO("FT_ID_THRESHOLD_SETUP\n"); + break; + + case FT_ID_DFIFO_DEPTH: + CFI_INFO("FT_ID_DFIFO_DEPTH\n"); + break; + + case FT_ID_TX_FIFO_DEPTH: + CFI_INFO("FT_ID_TX_FIFO_DEPTH\n"); + if ((retval = cfi_ep_set_tx_fifo_val(buf, pcd)) < 0) + return retval; + cfi->need_gadget_att = 0; + break; + + case FT_ID_RX_FIFO_DEPTH: + CFI_INFO("FT_ID_RX_FIFO_DEPTH\n"); + if ((retval = cfi_set_rx_fifo_val(buf, pcd)) < 0) + return retval; + cfi->need_gadget_att = 0; + break; + } + + return retval; +} + +#endif //DWC_UTE_CFI diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cfi.h b/drivers/usb/host/dwc_otg/dwc_otg_cfi.h new file mode 100644 index 000000000000..0215224b5124 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_cfi.h @@ -0,0 +1,319 @@ +/* ========================================================================== + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +#if !defined(__DWC_OTG_CFI_H__) +#define __DWC_OTG_CFI_H__ + +#include "dwc_otg_pcd.h" +#include "dwc_cfi_common.h" + +/** + * @file + * + * This file contains the CFI related OTG PCD specific common constants, interfaces + * (functions and macros) and data structures. + * + */ + +struct dwc_otg_pcd; +struct dwc_otg_pcd_ep; + +/** OTG CFI Features (properties) ID constants */ +/** This is a request for all Core Features */ +#define FT_ID_DMA_MODE 0x0001 +#define FT_ID_DMA_BUFFER_SETUP 0x0002 +#define FT_ID_DMA_BUFF_ALIGN 0x0003 +#define FT_ID_DMA_CONCAT_SETUP 0x0004 +#define FT_ID_DMA_CIRCULAR 0x0005 +#define FT_ID_THRESHOLD_SETUP 0x0006 +#define FT_ID_DFIFO_DEPTH 0x0007 +#define FT_ID_TX_FIFO_DEPTH 0x0008 +#define FT_ID_RX_FIFO_DEPTH 0x0009 + +/**********************************************************/ +#define CFI_INFO_DEF + +#ifdef CFI_INFO_DEF +#define CFI_INFO(fmt...) DWC_PRINTF("CFI: " fmt); +#else +#define CFI_INFO(fmt...) +#endif + +#define min(x,y) ({ \ + x < y ? x : y; }) + +#define max(x,y) ({ \ + x > y ? x : y; }) + +/** + * Descriptor DMA SG Buffer setup structure (SG buffer). This structure is + * also used for setting up a buffer for Circular DDMA. + */ +struct _ddma_sg_buffer_setup { +#define BS_SG_VAL_DESC_LEN 6 + /* The OUT EP address */ + uint8_t bOutEndpointAddress; + /* The IN EP address */ + uint8_t bInEndpointAddress; + /* Number of bytes to put between transfer segments (must be DWORD boundaries) */ + uint8_t bOffset; + /* The number of transfer segments (a DMA descriptors per each segment) */ + uint8_t bCount; + /* Size (in byte) of each transfer segment */ + uint16_t wSize; +} __attribute__ ((packed)); +typedef struct _ddma_sg_buffer_setup ddma_sg_buffer_setup_t; + +/** Descriptor DMA Concatenation Buffer setup structure */ +struct _ddma_concat_buffer_setup_hdr { +#define BS_CONCAT_VAL_HDR_LEN 4 + /* The endpoint for which the buffer is to be set up */ + uint8_t bEndpointAddress; + /* The count of descriptors to be used */ + uint8_t bDescCount; + /* The total size of the transfer */ + uint16_t wSize; +} __attribute__ ((packed)); +typedef struct _ddma_concat_buffer_setup_hdr ddma_concat_buffer_setup_hdr_t; + +/** Descriptor DMA Concatenation Buffer setup structure */ +struct _ddma_concat_buffer_setup { + /* The SG header */ + ddma_concat_buffer_setup_hdr_t hdr; + + /* The XFER sizes pointer (allocated dynamically) */ + uint16_t *wTxBytes; +} __attribute__ ((packed)); +typedef struct _ddma_concat_buffer_setup ddma_concat_buffer_setup_t; + +/** Descriptor DMA Alignment Buffer setup structure */ +struct _ddma_align_buffer_setup { +#define BS_ALIGN_VAL_HDR_LEN 2 + uint8_t bEndpointAddress; + uint8_t bAlign; +} __attribute__ ((packed)); +typedef struct _ddma_align_buffer_setup ddma_align_buffer_setup_t; + +/** Transmit FIFO Size setup structure */ +struct _tx_fifo_size_setup { + uint8_t bEndpointAddress; + uint16_t wDepth; +} __attribute__ ((packed)); +typedef struct _tx_fifo_size_setup tx_fifo_size_setup_t; + +/** Transmit FIFO Size setup structure */ +struct _rx_fifo_size_setup { + uint16_t wDepth; +} __attribute__ ((packed)); +typedef struct _rx_fifo_size_setup rx_fifo_size_setup_t; + +/** + * struct cfi_usb_ctrlrequest - the CFI implementation of the struct usb_ctrlrequest + * This structure encapsulates the standard usb_ctrlrequest and adds a pointer + * to the data returned in the data stage of a 3-stage Control Write requests. + */ +struct cfi_usb_ctrlrequest { + uint8_t bRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; + uint8_t *data; +} UPACKED; + +/*---------------------------------------------------------------------------*/ + +/** + * The CFI wrapper of the enabled and activated dwc_otg_pcd_ep structures. + * This structure is used to store the buffer setup data for any + * enabled endpoint in the PCD. + */ +struct cfi_ep { + /* Entry for the list container */ + dwc_list_link_t lh; + /* Pointer to the active PCD endpoint structure */ + struct dwc_otg_pcd_ep *ep; + /* The last descriptor in the chain of DMA descriptors of the endpoint */ + struct dwc_otg_dma_desc *dma_desc_last; + /* The SG feature value */ + ddma_sg_buffer_setup_t *bm_sg; + /* The Circular feature value */ + ddma_sg_buffer_setup_t *bm_circ; + /* The Concatenation feature value */ + ddma_concat_buffer_setup_t *bm_concat; + /* The Alignment feature value */ + ddma_align_buffer_setup_t *bm_align; + /* XFER length */ + uint32_t xfer_len; + /* + * Count of DMA descriptors currently used. + * The total should not exceed the MAX_DMA_DESCS_PER_EP value + * defined in the dwc_otg_cil.h + */ + uint32_t desc_count; +}; +typedef struct cfi_ep cfi_ep_t; + +typedef struct cfi_dma_buff { +#define CFI_IN_BUF_LEN 1024 +#define CFI_OUT_BUF_LEN 1024 + dma_addr_t addr; + uint8_t *buf; +} cfi_dma_buff_t; + +struct cfiobject; + +/** + * This is the interface for the CFI operations. + * + * @param ep_enable Called when any endpoint is enabled and activated. + * @param release Called when the CFI object is released and it needs to correctly + * deallocate the dynamic memory + * @param ctrl_write_complete Called when the data stage of the request is complete + */ +typedef struct cfi_ops { + int (*ep_enable) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd, + struct dwc_otg_pcd_ep * ep); + void *(*ep_alloc_buf) (struct cfiobject * cfi, struct dwc_otg_pcd * pcd, + struct dwc_otg_pcd_ep * ep, dma_addr_t * dma, + unsigned size, gfp_t flags); + void (*release) (struct cfiobject * cfi); + int (*ctrl_write_complete) (struct cfiobject * cfi, + struct dwc_otg_pcd * pcd); + void (*build_descriptors) (struct cfiobject * cfi, + struct dwc_otg_pcd * pcd, + struct dwc_otg_pcd_ep * ep, + dwc_otg_pcd_request_t * req); +} cfi_ops_t; + +struct cfiobject { + cfi_ops_t ops; + struct dwc_otg_pcd *pcd; + struct usb_gadget *gadget; + + /* Buffers used to send/receive CFI-related request data */ + cfi_dma_buff_t buf_in; + cfi_dma_buff_t buf_out; + + /* CFI specific Control request wrapper */ + struct cfi_usb_ctrlrequest ctrl_req; + + /* The list of active EP's in the PCD of type cfi_ep_t */ + dwc_list_link_t active_eps; + + /* This flag shall control the propagation of a specific request + * to the gadget's processing routines. + * 0 - no gadget handling + * 1 - the gadget needs to know about this request (w/o completing a status + * phase - just return a 0 to the _setup callback) + */ + uint8_t need_gadget_att; + + /* Flag indicating whether the status IN phase needs to be + * completed by the PCD + */ + uint8_t need_status_in_complete; +}; +typedef struct cfiobject cfiobject_t; + +#define DUMP_MSG + +#if defined(DUMP_MSG) +static inline void dump_msg(const u8 * buf, unsigned int length) +{ + unsigned int start, num, i; + char line[52], *p; + + if (length >= 512) + return; + + start = 0; + while (length > 0) { + num = min(length, 16u); + p = line; + for (i = 0; i < num; ++i) { + if (i == 8) + *p++ = ' '; + DWC_SPRINTF(p, " %02x", buf[i]); + p += 3; + } + *p = 0; + DWC_DEBUG("%6x: %s\n", start, line); + buf += num; + start += num; + length -= num; + } +} +#else +static inline void dump_msg(const u8 * buf, unsigned int length) +{ +} +#endif + +/** + * This function returns a pointer to cfi_ep_t object with the addr address. + */ +static inline struct cfi_ep *get_cfi_ep_by_addr(struct cfiobject *cfi, + uint8_t addr) +{ + struct cfi_ep *pcfiep; + dwc_list_link_t *tmp; + + DWC_LIST_FOREACH(tmp, &cfi->active_eps) { + pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh); + + if (pcfiep->ep->desc->bEndpointAddress == addr) { + return pcfiep; + } + } + + return NULL; +} + +/** + * This function returns a pointer to cfi_ep_t object that matches + * the dwc_otg_pcd_ep object. + */ +static inline struct cfi_ep *get_cfi_ep_by_pcd_ep(struct cfiobject *cfi, + struct dwc_otg_pcd_ep *ep) +{ + struct cfi_ep *pcfiep = NULL; + dwc_list_link_t *tmp; + + DWC_LIST_FOREACH(tmp, &cfi->active_eps) { + pcfiep = DWC_LIST_ENTRY(tmp, struct cfi_ep, lh); + if (pcfiep->ep == ep) { + return pcfiep; + } + } + return NULL; +} + +int cfi_setup(struct dwc_otg_pcd *pcd, struct cfi_usb_ctrlrequest *ctrl); + +#endif /* (__DWC_OTG_CFI_H__) */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cil.c b/drivers/usb/host/dwc_otg/dwc_otg_cil.c new file mode 100644 index 000000000000..ccfe6b5292bf --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil.c @@ -0,0 +1,5410 @@ +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.c $ + * $Revision: #159 $ + * $Date: 2009/04/21 $ + * $Change: 1237465 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +/** @file + * + * The Core Interface Layer provides basic services for accessing and + * managing the DWC_otg hardware. These services are used by both the + * Host Controller Driver and the Peripheral Controller Driver. + * + * The CIL manages the memory map for the core so that the HCD and PCD + * don't have to do this separately. It also handles basic tasks like + * reading/writing the registers and data FIFOs in the controller. + * Some of the data access functions provide encapsulation of several + * operations required to perform a task, such as writing multiple + * registers to start a transfer. Finally, the CIL performs basic + * services that are not specific to either the host or device modes + * of operation. These services include management of the OTG Host + * Negotiation Protocol (HNP) and Session Request Protocol (SRP). A + * Diagnostic API is also provided to allow testing of the controller + * hardware. + * + * The Core Interface Layer has the following requirements: + * - Provides basic controller operations. + * - Minimal use of OS services. + * - The OS services used will be abstracted by using inline functions + * or macros. + * + */ + +#include "dwc_os.h" +#include "dwc_otg_regs.h" +#include "dwc_otg_cil.h" + +static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if); + +/** + * This function is called to initialize the DWC_otg CSR data + * structures. The register addresses in the device and host + * structures are initialized from the base address supplied by the + * caller. The calling function must make the OS calls to get the + * base address of the DWC_otg controller registers. The core_params + * argument holds the parameters that specify how the core should be + * configured. + * + * @param reg_base_addr Base address of DWC_otg core registers + * + */ +dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * reg_base_addr) +{ + dwc_otg_core_if_t *core_if = 0; + dwc_otg_dev_if_t *dev_if = 0; + dwc_otg_host_if_t *host_if = 0; + uint8_t *reg_base = (uint8_t *) reg_base_addr; + int i = 0; + + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, reg_base_addr); + + core_if = dwc_alloc(sizeof(dwc_otg_core_if_t)); + + if (core_if == 0) { + DWC_DEBUGPL(DBG_CIL, + "Allocation of dwc_otg_core_if_t failed\n"); + return 0; + } + core_if->core_global_regs = (dwc_otg_core_global_regs_t *) reg_base; + + /* + * Allocate the Device Mode structures. + */ + dev_if = dwc_alloc(sizeof(dwc_otg_dev_if_t)); + + if (dev_if == 0) { + DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_dev_if_t failed\n"); + dwc_free(core_if); + return 0; + } + + dev_if->dev_global_regs = + (dwc_otg_device_global_regs_t *) (reg_base + + DWC_DEV_GLOBAL_REG_OFFSET); + + for (i = 0; i < MAX_EPS_CHANNELS; i++) { + dev_if->in_ep_regs[i] = (dwc_otg_dev_in_ep_regs_t *) + (reg_base + DWC_DEV_IN_EP_REG_OFFSET + + (i * DWC_EP_REG_OFFSET)); + + dev_if->out_ep_regs[i] = (dwc_otg_dev_out_ep_regs_t *) + (reg_base + DWC_DEV_OUT_EP_REG_OFFSET + + (i * DWC_EP_REG_OFFSET)); + DWC_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p\n", + i, &dev_if->in_ep_regs[i]->diepctl); + DWC_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p\n", + i, &dev_if->out_ep_regs[i]->doepctl); + } + + dev_if->speed = 0; // unknown + + core_if->dev_if = dev_if; + + /* + * Allocate the Host Mode structures. + */ + host_if = dwc_alloc(sizeof(dwc_otg_host_if_t)); + + if (host_if == 0) { + DWC_DEBUGPL(DBG_CIL, + "Allocation of dwc_otg_host_if_t failed\n"); + dwc_free(dev_if); + dwc_free(core_if); + return 0; + } + + host_if->host_global_regs = (dwc_otg_host_global_regs_t *) + (reg_base + DWC_OTG_HOST_GLOBAL_REG_OFFSET); + + host_if->hprt0 = + (uint32_t *) (reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET); + + for (i = 0; i < MAX_EPS_CHANNELS; i++) { + host_if->hc_regs[i] = (dwc_otg_hc_regs_t *) + (reg_base + DWC_OTG_HOST_CHAN_REGS_OFFSET + + (i * DWC_OTG_CHAN_REGS_OFFSET)); + DWC_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n", + i, &host_if->hc_regs[i]->hcchar); + } + + host_if->num_host_channels = MAX_EPS_CHANNELS; + core_if->host_if = host_if; + + for (i = 0; i < MAX_EPS_CHANNELS; i++) { + core_if->data_fifo[i] = + (uint32_t *) (reg_base + DWC_OTG_DATA_FIFO_OFFSET + + (i * DWC_OTG_DATA_FIFO_SIZE)); + DWC_DEBUGPL(DBG_CILV, "data_fifo[%d]=0x%08x\n", + i, (unsigned)core_if->data_fifo[i]); + } + + core_if->pcgcctl = (uint32_t *) (reg_base + DWC_OTG_PCGCCTL_OFFSET); + + /* Initiate lx_state to L3 disconnected state */ + core_if->lx_state = DWC_OTG_L3; + /* + * Store the contents of the hardware configuration registers here for + * easy access later. + */ + core_if->hwcfg1.d32 = + dwc_read_reg32(&core_if->core_global_regs->ghwcfg1); + core_if->hwcfg2.d32 = + dwc_read_reg32(&core_if->core_global_regs->ghwcfg2); + core_if->hwcfg3.d32 = + dwc_read_reg32(&core_if->core_global_regs->ghwcfg3); + core_if->hwcfg4.d32 = + dwc_read_reg32(&core_if->core_global_regs->ghwcfg4); + + DWC_DEBUGPL(DBG_CILV, "hwcfg1=%08x\n", core_if->hwcfg1.d32); + DWC_DEBUGPL(DBG_CILV, "hwcfg2=%08x\n", core_if->hwcfg2.d32); + DWC_DEBUGPL(DBG_CILV, "hwcfg3=%08x\n", core_if->hwcfg3.d32); + DWC_DEBUGPL(DBG_CILV, "hwcfg4=%08x\n", core_if->hwcfg4.d32); + + core_if->hcfg.d32 = + dwc_read_reg32(&core_if->host_if->host_global_regs->hcfg); + core_if->dcfg.d32 = + dwc_read_reg32(&core_if->dev_if->dev_global_regs->dcfg); + + DWC_DEBUGPL(DBG_CILV, "hcfg=%08x\n", core_if->hcfg.d32); + DWC_DEBUGPL(DBG_CILV, "dcfg=%08x\n", core_if->dcfg.d32); + + DWC_DEBUGPL(DBG_CILV, "op_mode=%0x\n", core_if->hwcfg2.b.op_mode); + DWC_DEBUGPL(DBG_CILV, "arch=%0x\n", core_if->hwcfg2.b.architecture); + DWC_DEBUGPL(DBG_CILV, "num_dev_ep=%d\n", core_if->hwcfg2.b.num_dev_ep); + DWC_DEBUGPL(DBG_CILV, "num_host_chan=%d\n", + core_if->hwcfg2.b.num_host_chan); + DWC_DEBUGPL(DBG_CILV, "nonperio_tx_q_depth=0x%0x\n", + core_if->hwcfg2.b.nonperio_tx_q_depth); + DWC_DEBUGPL(DBG_CILV, "host_perio_tx_q_depth=0x%0x\n", + core_if->hwcfg2.b.host_perio_tx_q_depth); + DWC_DEBUGPL(DBG_CILV, "dev_token_q_depth=0x%0x\n", + core_if->hwcfg2.b.dev_token_q_depth); + + DWC_DEBUGPL(DBG_CILV, "Total FIFO SZ=%d\n", + core_if->hwcfg3.b.dfifo_depth); + DWC_DEBUGPL(DBG_CILV, "xfer_size_cntr_width=%0x\n", + core_if->hwcfg3.b.xfer_size_cntr_width); + + /* + * Set the SRP sucess bit for FS-I2c + */ + core_if->srp_success = 0; + core_if->srp_timer_started = 0; + + /* + * Create new workqueue and init works + */ + core_if->wq_otg = DWC_WORKQ_ALLOC("dwc_otg"); + if (core_if->wq_otg == 0) { + DWC_WARN("DWC_WORKQ_ALLOC failed\n"); + dwc_free(host_if); + dwc_free(dev_if); + dwc_free(core_if); + return 0; + } + + core_if->snpsid = dwc_read_reg32(&core_if->core_global_regs->gsnpsid); + + DWC_PRINTF("Core Release: %x.%x%x%x\n", + (core_if->snpsid >> 12 & 0xF), + (core_if->snpsid >> 8 & 0xF), + (core_if->snpsid >> 4 & 0xF), (core_if->snpsid & 0xF)); + + core_if->wkp_timer = DWC_TIMER_ALLOC("Wake Up Timer", + w_wakeup_detected, core_if); + if (core_if->wkp_timer == 0) { + DWC_WARN("DWC_TIMER_ALLOC failed\n"); + dwc_free(host_if); + dwc_free(dev_if); + DWC_WORKQ_FREE(core_if->wq_otg); + dwc_free(core_if); + return 0; + } + + if (dwc_otg_setup_params(core_if)) { + DWC_WARN("Error while setting core params\n"); + } + + return core_if; +} + +/** + * This function frees the structures allocated by dwc_otg_cil_init(). + * + * @param core_if The core interface pointer returned from + * dwc_otg_cil_init(). + * + */ +void dwc_otg_cil_remove(dwc_otg_core_if_t * core_if) +{ + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if); + + /* Disable all interrupts */ + dwc_modify_reg32(&core_if->core_global_regs->gahbcfg, 1, 0); + dwc_write_reg32(&core_if->core_global_regs->gintmsk, 0); + + if (core_if->wq_otg) { + DWC_WORKQ_WAIT_WORK_DONE(core_if->wq_otg, 500); + DWC_WORKQ_FREE(core_if->wq_otg); + } + if (core_if->dev_if) { + dwc_free(core_if->dev_if); + } + if (core_if->host_if) { + dwc_free(core_if->host_if); + } + dwc_free(core_if); + DWC_TIMER_FREE(core_if->wkp_timer); + DWC_FREE(core_if->core_params); +} + +/** + * This function enables the controller's Global Interrupt in the AHB Config + * register. + * + * @param core_if Programming view of DWC_otg controller. + */ +void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * core_if) +{ + gahbcfg_data_t ahbcfg = {.d32 = 0 }; + ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ + dwc_modify_reg32(&core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32); +} + +/** + * This function disables the controller's Global Interrupt in the AHB Config + * register. + * + * @param core_if Programming view of DWC_otg controller. + */ +void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * core_if) +{ + gahbcfg_data_t ahbcfg = {.d32 = 0 }; + ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ + DWC_PRINTF("%x -> %x\n", (unsigned int)&core_if->core_global_regs->gahbcfg, ahbcfg.d32); + dwc_modify_reg32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0); +} + +/** + * This function initializes the commmon interrupts, used in both + * device and host modes. + * + * @param core_if Programming view of the DWC_otg controller + * + */ +static void dwc_otg_enable_common_interrupts(dwc_otg_core_if_t * core_if) +{ + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; + gintmsk_data_t intr_mask = {.d32 = 0 }; + + /* Clear any pending OTG Interrupts */ + dwc_write_reg32(&global_regs->gotgint, 0xFFFFFFFF); + + /* Clear any pending interrupts */ + dwc_write_reg32(&global_regs->gintsts, 0xFFFFFFFF); + + /* + * Enable the interrupts in the GINTMSK. + */ + intr_mask.b.modemismatch = 1; + intr_mask.b.otgintr = 1; + + if (!core_if->dma_enable) { + intr_mask.b.rxstsqlvl = 1; + } + + intr_mask.b.conidstschng = 1; + intr_mask.b.wkupintr = 1; + intr_mask.b.disconnect = 1; + intr_mask.b.usbsuspend = 1; + intr_mask.b.sessreqintr = 1; +#ifdef CONFIG_USB_DWC_OTG_LPM + if (core_if->core_params->lpm_enable) { + intr_mask.b.lpmtranrcvd = 1; + } +#endif + dwc_write_reg32(&global_regs->gintmsk, intr_mask.d32); +} + +/** + * Initializes the FSLSPClkSel field of the HCFG register depending on the PHY + * type. + */ +static void init_fslspclksel(dwc_otg_core_if_t * core_if) +{ + uint32_t val; + hcfg_data_t hcfg; + + if (((core_if->hwcfg2.b.hs_phy_type == 2) && + (core_if->hwcfg2.b.fs_phy_type == 1) && + (core_if->core_params->ulpi_fs_ls)) || + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) { + /* Full speed PHY */ + val = DWC_HCFG_48_MHZ; + } else { + /* High speed PHY running at full speed or high speed */ + val = DWC_HCFG_30_60_MHZ; + } + + DWC_DEBUGPL(DBG_CIL, "Initializing HCFG.FSLSPClkSel to 0x%1x\n", val); + hcfg.d32 = dwc_read_reg32(&core_if->host_if->host_global_regs->hcfg); + hcfg.b.fslspclksel = val; + dwc_write_reg32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32); +} + +/** + * Initializes the DevSpd field of the DCFG register depending on the PHY type + * and the enumeration speed of the device. + */ +static void init_devspd(dwc_otg_core_if_t * core_if) +{ + uint32_t val; + dcfg_data_t dcfg; + + if (((core_if->hwcfg2.b.hs_phy_type == 2) && + (core_if->hwcfg2.b.fs_phy_type == 1) && + (core_if->core_params->ulpi_fs_ls)) || + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) { + /* Full speed PHY */ + val = 0x3; + } else if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) { + /* High speed PHY running at full speed */ + val = 0x1; + } else { + /* High speed PHY running at high speed */ + val = 0x0; + } + + DWC_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val); + + dcfg.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dcfg); + dcfg.b.devspd = val; + dwc_write_reg32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32); +} + +/** + * This function calculates the number of IN EPS + * using GHWCFG1 and GHWCFG2 registers values + * + * @param core_if Programming view of the DWC_otg controller + */ +static uint32_t calc_num_in_eps(dwc_otg_core_if_t * core_if) +{ + uint32_t num_in_eps = 0; + uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep; + uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 3; + uint32_t num_tx_fifos = core_if->hwcfg4.b.num_in_eps; + int i; + + for (i = 0; i < num_eps; ++i) { + if (!(hwcfg1 & 0x1)) + num_in_eps++; + + hwcfg1 >>= 2; + } + + if (core_if->hwcfg4.b.ded_fifo_en) { + num_in_eps = + (num_in_eps > num_tx_fifos) ? num_tx_fifos : num_in_eps; + } + + return num_in_eps; +} + +/** + * This function calculates the number of OUT EPS + * using GHWCFG1 and GHWCFG2 registers values + * + * @param core_if Programming view of the DWC_otg controller + */ +static uint32_t calc_num_out_eps(dwc_otg_core_if_t * core_if) +{ + uint32_t num_out_eps = 0; + uint32_t num_eps = core_if->hwcfg2.b.num_dev_ep; + uint32_t hwcfg1 = core_if->hwcfg1.d32 >> 2; + int i; + + for (i = 0; i < num_eps; ++i) { + if (!(hwcfg1 & 0x1)) + num_out_eps++; + + hwcfg1 >>= 2; + } + return num_out_eps; +} + +/** + * This function initializes the DWC_otg controller registers and + * prepares the core for device mode or host mode operation. + * + * @param core_if Programming view of the DWC_otg controller + * + */ +void dwc_otg_core_init(dwc_otg_core_if_t * core_if) +{ + int i = 0; + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; + dwc_otg_dev_if_t *dev_if = core_if->dev_if; + gahbcfg_data_t ahbcfg = {.d32 = 0 }; + gusbcfg_data_t usbcfg = {.d32 = 0 }; + gi2cctl_data_t i2cctl = {.d32 = 0 }; + + DWC_DEBUGPL(DBG_CILV, "dwc_otg_core_init(%p) regs at %p\n", + core_if, global_regs); + + /* Common Initialization */ + + usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); + + /* Program the ULPI External VBUS bit if needed */ + usbcfg.b.ulpi_ext_vbus_drv = + (core_if->core_params->phy_ulpi_ext_vbus == + DWC_PHY_ULPI_EXTERNAL_VBUS) ? 1 : 0; + + /* Set external TS Dline pulsing */ + usbcfg.b.term_sel_dl_pulse = + (core_if->core_params->ts_dline == 1) ? 1 : 0; + dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32); + + /* Reset the Controller */ + dwc_otg_core_reset(core_if); + + /* Initialize parameters from Hardware configuration registers. */ + dev_if->num_in_eps = calc_num_in_eps(core_if); + dev_if->num_out_eps = calc_num_out_eps(core_if); + + DWC_DEBUGPL(DBG_CIL, "num_dev_perio_in_ep=%d\n", + core_if->hwcfg4.b.num_dev_perio_in_ep); + + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) { + dev_if->perio_tx_fifo_size[i] = + dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i]) >> 16; + DWC_DEBUGPL(DBG_CIL, "Periodic Tx FIFO SZ #%d=0x%0x\n", + i, dev_if->perio_tx_fifo_size[i]); + } + + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) { + dev_if->tx_fifo_size[i] = + dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i]) >> 16; + DWC_DEBUGPL(DBG_CIL, "Tx FIFO SZ #%d=0x%0x\n", + i, dev_if->perio_tx_fifo_size[i]); + } + + core_if->total_fifo_size = core_if->hwcfg3.b.dfifo_depth; + core_if->rx_fifo_size = dwc_read_reg32(&global_regs->grxfsiz); + core_if->nperio_tx_fifo_size = + dwc_read_reg32(&global_regs->gnptxfsiz) >> 16; + + DWC_DEBUGPL(DBG_CIL, "Total FIFO SZ=%d\n", core_if->total_fifo_size); + DWC_DEBUGPL(DBG_CIL, "Rx FIFO SZ=%d\n", core_if->rx_fifo_size); + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO SZ=%d\n", + core_if->nperio_tx_fifo_size); + + /* This programming sequence needs to happen in FS mode before any other + * programming occurs */ + if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) && + (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) { + /* If FS mode with FS PHY */ + + /* core_init() is now called on every switch so only call the + * following for the first time through. */ + if (!core_if->phy_init_done) { + core_if->phy_init_done = 1; + DWC_DEBUGPL(DBG_CIL, "FS_PHY detected\n"); + usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); + usbcfg.b.physel = 1; + dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32); + + /* Reset after a PHY select */ + dwc_otg_core_reset(core_if); + } + + /* Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also + * do this on HNP Dev/Host mode switches (done in dev_init and + * host_init). */ + if (dwc_otg_is_host_mode(core_if)) { + init_fslspclksel(core_if); + } else { + init_devspd(core_if); + } + + if (core_if->core_params->i2c_enable) { + DWC_DEBUGPL(DBG_CIL, "FS_PHY Enabling I2c\n"); + /* Program GUSBCFG.OtgUtmifsSel to I2C */ + usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); + usbcfg.b.otgutmifssel = 1; + dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32); + + /* Program GI2CCTL.I2CEn */ + i2cctl.d32 = dwc_read_reg32(&global_regs->gi2cctl); + i2cctl.b.i2cdevaddr = 1; + i2cctl.b.i2cen = 0; + dwc_write_reg32(&global_regs->gi2cctl, i2cctl.d32); + i2cctl.b.i2cen = 1; + dwc_write_reg32(&global_regs->gi2cctl, i2cctl.d32); + } + + } /* endif speed == DWC_SPEED_PARAM_FULL */ + else { + /* High speed PHY. */ + if (!core_if->phy_init_done) { + core_if->phy_init_done = 1; + /* HS PHY parameters. These parameters are preserved + * during soft reset so only program the first time. Do + * a soft reset immediately after setting phyif. */ + usbcfg.b.ulpi_utmi_sel = core_if->core_params->phy_type; + if (usbcfg.b.ulpi_utmi_sel == 1) { + /* ULPI interface */ + usbcfg.b.phyif = 0; + usbcfg.b.ddrsel = + core_if->core_params->phy_ulpi_ddr; + } else { + /* UTMI+ interface */ + if (core_if->core_params->phy_utmi_width == 16) { + usbcfg.b.phyif = 1; + + } else { + usbcfg.b.phyif = 0; + } + + } + + dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32); + /* Reset after setting the PHY parameters */ + dwc_otg_core_reset(core_if); + } + } + + if ((core_if->hwcfg2.b.hs_phy_type == 2) && + (core_if->hwcfg2.b.fs_phy_type == 1) && + (core_if->core_params->ulpi_fs_ls)) { + DWC_DEBUGPL(DBG_CIL, "Setting ULPI FSLS\n"); + usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); + usbcfg.b.ulpi_fsls = 1; + usbcfg.b.ulpi_clk_sus_m = 1; + dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32); + } else { + usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); + usbcfg.b.ulpi_fsls = 0; + usbcfg.b.ulpi_clk_sus_m = 0; + dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32); + } + + /* Program the GAHBCFG Register. */ + switch (core_if->hwcfg2.b.architecture) { + + case DWC_SLAVE_ONLY_ARCH: + DWC_DEBUGPL(DBG_CIL, "Slave Only Mode\n"); + ahbcfg.b.nptxfemplvl_txfemplvl = + DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY; + ahbcfg.b.ptxfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY; + core_if->dma_enable = 0; + core_if->dma_desc_enable = 0; + break; + + case DWC_EXT_DMA_ARCH: + DWC_DEBUGPL(DBG_CIL, "External DMA Mode\n"); + { + uint8_t brst_sz = core_if->core_params->dma_burst_size; + ahbcfg.b.hburstlen = 0; + while (brst_sz > 1) { + ahbcfg.b.hburstlen++; + brst_sz >>= 1; + } + } + core_if->dma_enable = (core_if->core_params->dma_enable != 0); + core_if->dma_desc_enable = + (core_if->core_params->dma_desc_enable != 0); + break; + + case DWC_INT_DMA_ARCH: + DWC_DEBUGPL(DBG_CIL, "Internal DMA Mode\n"); + /*ahbcfg.b.hburstlen = DWC_GAHBCFG_INT_DMA_BURST_INCR; */ + ahbcfg.b.hburstlen = (1<<3)|(0<<0); /* WRESP=1, max 4 beats */ + core_if->dma_enable = (core_if->core_params->dma_enable != 0); + core_if->dma_desc_enable = + (core_if->core_params->dma_desc_enable != 0); + break; + + } + if (core_if->dma_enable) { + if (core_if->dma_desc_enable) { + DWC_PRINTF("Using Descriptor DMA mode\n"); + } else { + DWC_PRINTF("Using Buffer DMA mode\n"); + + } + } else { + DWC_PRINTF("Using Slave mode\n"); + core_if->dma_desc_enable = 0; + } + + ahbcfg.b.dmaenable = core_if->dma_enable; + dwc_write_reg32(&global_regs->gahbcfg, ahbcfg.d32); + + core_if->en_multiple_tx_fifo = core_if->hwcfg4.b.ded_fifo_en; + + core_if->pti_enh_enable = core_if->core_params->pti_enable != 0; + core_if->multiproc_int_enable = core_if->core_params->mpi_enable; + DWC_PRINTF("Periodic Transfer Interrupt Enhancement - %s\n", + ((core_if->pti_enh_enable) ? "enabled" : "disabled")); + DWC_PRINTF("Multiprocessor Interrupt Enhancement - %s\n", + ((core_if->multiproc_int_enable) ? "enabled" : "disabled")); + + /* + * Program the GUSBCFG register. + */ + usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); + + switch (core_if->hwcfg2.b.op_mode) { + case DWC_MODE_HNP_SRP_CAPABLE: + usbcfg.b.hnpcap = (core_if->core_params->otg_cap == + DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE); + usbcfg.b.srpcap = (core_if->core_params->otg_cap != + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE); + break; + + case DWC_MODE_SRP_ONLY_CAPABLE: + usbcfg.b.hnpcap = 0; + usbcfg.b.srpcap = (core_if->core_params->otg_cap != + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE); + break; + + case DWC_MODE_NO_HNP_SRP_CAPABLE: + usbcfg.b.hnpcap = 0; + usbcfg.b.srpcap = 0; + break; + + case DWC_MODE_SRP_CAPABLE_DEVICE: + usbcfg.b.hnpcap = 0; + usbcfg.b.srpcap = (core_if->core_params->otg_cap != + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE); + break; + + case DWC_MODE_NO_SRP_CAPABLE_DEVICE: + usbcfg.b.hnpcap = 0; + usbcfg.b.srpcap = 0; + break; + + case DWC_MODE_SRP_CAPABLE_HOST: + usbcfg.b.hnpcap = 0; + usbcfg.b.srpcap = (core_if->core_params->otg_cap != + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE); + break; + + case DWC_MODE_NO_SRP_CAPABLE_HOST: + usbcfg.b.hnpcap = 0; + usbcfg.b.srpcap = 0; + break; + } + + dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32); + +#ifdef CONFIG_USB_DWC_OTG_LPM + if (core_if->core_params->lpm_enable) { + glpmcfg_data_t lpmcfg = {.d32 = 0 }; + + /* To enable LPM support set lpm_cap_en bit */ + lpmcfg.b.lpm_cap_en = 1; + + /* Make AppL1Res ACK */ + lpmcfg.b.appl_resp = 1; + + /* Retry 3 times */ + lpmcfg.b.retry_count = 3; + + dwc_modify_reg32(&core_if->core_global_regs->glpmcfg, + 0, lpmcfg.d32); + + } +#endif + if (core_if->core_params->ic_usb_cap) { + gusbcfg_data_t gusbcfg = {.d32 = 0 }; + gusbcfg.b.ic_usb_cap = 1; + dwc_modify_reg32(&core_if->core_global_regs->gusbcfg, + 0, gusbcfg.d32); + } + + /* Enable common interrupts */ + dwc_otg_enable_common_interrupts(core_if); + + /* Do device or host intialization based on mode during PCD + * and HCD initialization */ + if (dwc_otg_is_host_mode(core_if)) { + DWC_DEBUGPL(DBG_ANY, "Host Mode\n"); + core_if->op_state = A_HOST; + } else { + DWC_DEBUGPL(DBG_ANY, "Device Mode\n"); + core_if->op_state = B_PERIPHERAL; +#ifdef DWC_DEVICE_ONLY + dwc_otg_core_dev_init(core_if); +#endif + } +} + +/** + * This function enables the Device mode interrupts. + * + * @param core_if Programming view of DWC_otg controller + */ +void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * core_if) +{ + gintmsk_data_t intr_mask = {.d32 = 0 }; + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; + + DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__); + + /* Disable all interrupts. */ + dwc_write_reg32(&global_regs->gintmsk, 0); + + /* Clear any pending interrupts */ + dwc_write_reg32(&global_regs->gintsts, 0xFFFFFFFF); + + /* Enable the common interrupts */ + dwc_otg_enable_common_interrupts(core_if); + + /* Enable interrupts */ + intr_mask.b.usbreset = 1; + intr_mask.b.enumdone = 1; + + if (!core_if->multiproc_int_enable) { + intr_mask.b.inepintr = 1; + intr_mask.b.outepintr = 1; + } + + intr_mask.b.erlysuspend = 1; + + if (core_if->en_multiple_tx_fifo == 0) { + intr_mask.b.epmismatch = 1; + } +#ifdef DWC_EN_ISOC + if (core_if->dma_enable) { + if (core_if->dma_desc_enable == 0) { + if (core_if->pti_enh_enable) { + dctl_data_t dctl = {.d32 = 0 }; + dctl.b.ifrmnum = 1; + dwc_modify_reg32(&core_if->dev_if-> + dev_global_regs->dctl, 0, + dctl.d32); + } else { + intr_mask.b.incomplisoin = 1; + intr_mask.b.incomplisoout = 1; + } + } + } else { + intr_mask.b.incomplisoin = 1; + intr_mask.b.incomplisoout = 1; + } +#endif /* DWC_EN_ISOC */ + + /** @todo NGS: Should this be a module parameter? */ +#ifdef USE_PERIODIC_EP + intr_mask.b.isooutdrop = 1; + intr_mask.b.eopframe = 1; + intr_mask.b.incomplisoin = 1; + intr_mask.b.incomplisoout = 1; +#endif + + dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32); + + DWC_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__, + dwc_read_reg32(&global_regs->gintmsk)); +} + +/** + * This function initializes the DWC_otg controller registers for + * device mode. + * + * @param core_if Programming view of DWC_otg controller + * + */ +void dwc_otg_core_dev_init(dwc_otg_core_if_t * core_if) +{ + int i; + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; + dwc_otg_dev_if_t *dev_if = core_if->dev_if; + dwc_otg_core_params_t *params = core_if->core_params; + dcfg_data_t dcfg = {.d32 = 0 }; + grstctl_t resetctl = {.d32 = 0 }; + uint32_t rx_fifo_size; + fifosize_data_t nptxfifosize; + fifosize_data_t txfifosize; + dthrctl_data_t dthrctl; + fifosize_data_t ptxfifosize; + + /* Restart the Phy Clock */ + dwc_write_reg32(core_if->pcgcctl, 0); + + /* Device configuration register */ + init_devspd(core_if); + dcfg.d32 = dwc_read_reg32(&dev_if->dev_global_regs->dcfg); + dcfg.b.descdma = (core_if->dma_desc_enable) ? 1 : 0; + dcfg.b.perfrint = DWC_DCFG_FRAME_INTERVAL_80; + + dwc_write_reg32(&dev_if->dev_global_regs->dcfg, dcfg.d32); + + /* Configure data FIFO sizes */ + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) { + DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n", + core_if->total_fifo_size); + DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n", + params->dev_rx_fifo_size); + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n", + params->dev_nperio_tx_fifo_size); + + /* Rx FIFO */ + DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n", + dwc_read_reg32(&global_regs->grxfsiz)); + +#ifdef DWC_UTE_CFI + core_if->pwron_rxfsiz = dwc_read_reg32(&global_regs->grxfsiz); + core_if->init_rxfsiz = params->dev_rx_fifo_size; +#endif + rx_fifo_size = params->dev_rx_fifo_size; + dwc_write_reg32(&global_regs->grxfsiz, rx_fifo_size); + + DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n", + dwc_read_reg32(&global_regs->grxfsiz)); + + /** Set Periodic Tx FIFO Mask all bits 0 */ + core_if->p_tx_msk = 0; + + /** Set Tx FIFO Mask all bits 0 */ + core_if->tx_msk = 0; + + if (core_if->en_multiple_tx_fifo == 0) { + /* Non-periodic Tx FIFO */ + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n", + dwc_read_reg32(&global_regs->gnptxfsiz)); + + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size; + nptxfifosize.b.startaddr = params->dev_rx_fifo_size; + + dwc_write_reg32(&global_regs->gnptxfsiz, + nptxfifosize.d32); + + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n", + dwc_read_reg32(&global_regs->gnptxfsiz)); + + /**@todo NGS: Fix Periodic FIFO Sizing! */ + /* + * Periodic Tx FIFOs These FIFOs are numbered from 1 to 15. + * Indexes of the FIFO size module parameters in the + * dev_perio_tx_fifo_size array and the FIFO size registers in + * the dptxfsiz array run from 0 to 14. + */ + /** @todo Finish debug of this */ + ptxfifosize.b.startaddr = + nptxfifosize.b.startaddr + nptxfifosize.b.depth; + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; + i++) { + ptxfifosize.b.depth = + params->dev_perio_tx_fifo_size[i]; + DWC_DEBUGPL(DBG_CIL, + "initial dptxfsiz_dieptxf[%d]=%08x\n", + i, + dwc_read_reg32(&global_regs-> + dptxfsiz_dieptxf + [i])); + dwc_write_reg32(&global_regs-> + dptxfsiz_dieptxf[i], + ptxfifosize.d32); + DWC_DEBUGPL(DBG_CIL, + "new dptxfsiz_dieptxf[%d]=%08x\n", + i, + dwc_read_reg32(&global_regs-> + dptxfsiz_dieptxf + [i])); + ptxfifosize.b.startaddr += ptxfifosize.b.depth; + } + } else { + /* + * Tx FIFOs These FIFOs are numbered from 1 to 15. + * Indexes of the FIFO size module parameters in the + * dev_tx_fifo_size array and the FIFO size registers in + * the dptxfsiz_dieptxf array run from 0 to 14. + */ + + /* Non-periodic Tx FIFO */ + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n", + dwc_read_reg32(&global_regs->gnptxfsiz)); + +#ifdef DWC_UTE_CFI + core_if->pwron_gnptxfsiz = + (dwc_read_reg32(&global_regs->gnptxfsiz) >> 16); + core_if->init_gnptxfsiz = + params->dev_nperio_tx_fifo_size; +#endif + nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size; + nptxfifosize.b.startaddr = params->dev_rx_fifo_size; + + dwc_write_reg32(&global_regs->gnptxfsiz, + nptxfifosize.d32); + + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n", + dwc_read_reg32(&global_regs->gnptxfsiz)); + + txfifosize.b.startaddr = + nptxfifosize.b.startaddr + nptxfifosize.b.depth; + + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; i++) { + + txfifosize.b.depth = + params->dev_tx_fifo_size[i]; + + DWC_DEBUGPL(DBG_CIL, + "initial dptxfsiz_dieptxf[%d]=%08x\n", + i, + dwc_read_reg32(&global_regs-> + dptxfsiz_dieptxf + [i])); + +#ifdef DWC_UTE_CFI + core_if->pwron_txfsiz[i] = + (dwc_read_reg32 + (&global_regs->dptxfsiz_dieptxf[i]) >> 16); + core_if->init_txfsiz[i] = + params->dev_tx_fifo_size[i]; +#endif + dwc_write_reg32(&global_regs-> + dptxfsiz_dieptxf[i], + txfifosize.d32); + + DWC_DEBUGPL(DBG_CIL, + "new dptxfsiz_dieptxf[%d]=%08x\n", + i, + dwc_read_reg32(&global_regs-> + dptxfsiz_dieptxf + [i])); + + txfifosize.b.startaddr += txfifosize.b.depth; + } + } + } + /* Flush the FIFOs */ + dwc_otg_flush_tx_fifo(core_if, 0x10); /* all Tx FIFOs */ + dwc_otg_flush_rx_fifo(core_if); + + /* Flush the Learning Queue. */ + resetctl.b.intknqflsh = 1; + dwc_write_reg32(&core_if->core_global_regs->grstctl, resetctl.d32); + + /* Clear all pending Device Interrupts */ + /** @todo - if the condition needed to be checked + * or in any case all pending interrutps should be cleared? + */ + if (core_if->multiproc_int_enable) { + for (i = 0; i < core_if->dev_if->num_in_eps; ++i) { + dwc_write_reg32(&dev_if->dev_global_regs-> + diepeachintmsk[i], 0); + } + + for (i = 0; i < core_if->dev_if->num_out_eps; ++i) { + dwc_write_reg32(&dev_if->dev_global_regs-> + doepeachintmsk[i], 0); + } + + dwc_write_reg32(&dev_if->dev_global_regs->deachint, 0xFFFFFFFF); + dwc_write_reg32(&dev_if->dev_global_regs->deachintmsk, 0); + } else { + dwc_write_reg32(&dev_if->dev_global_regs->diepmsk, 0); + dwc_write_reg32(&dev_if->dev_global_regs->doepmsk, 0); + dwc_write_reg32(&dev_if->dev_global_regs->daint, 0xFFFFFFFF); + dwc_write_reg32(&dev_if->dev_global_regs->daintmsk, 0); + } + + for (i = 0; i <= dev_if->num_in_eps; i++) { + depctl_data_t depctl; + depctl.d32 = dwc_read_reg32(&dev_if->in_ep_regs[i]->diepctl); + if (depctl.b.epena) { + depctl.d32 = 0; + depctl.b.epdis = 1; + depctl.b.snak = 1; + } else { + depctl.d32 = 0; + } + + dwc_write_reg32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32); + + dwc_write_reg32(&dev_if->in_ep_regs[i]->dieptsiz, 0); + dwc_write_reg32(&dev_if->in_ep_regs[i]->diepdma, 0); + dwc_write_reg32(&dev_if->in_ep_regs[i]->diepint, 0xFF); + } + + for (i = 0; i <= dev_if->num_out_eps; i++) { + depctl_data_t depctl; + depctl.d32 = dwc_read_reg32(&dev_if->out_ep_regs[i]->doepctl); + if (depctl.b.epena) { + depctl.d32 = 0; + depctl.b.epdis = 1; + depctl.b.snak = 1; + } else { + depctl.d32 = 0; + } + + dwc_write_reg32(&dev_if->out_ep_regs[i]->doepctl, depctl.d32); + + dwc_write_reg32(&dev_if->out_ep_regs[i]->doeptsiz, 0); + dwc_write_reg32(&dev_if->out_ep_regs[i]->doepdma, 0); + dwc_write_reg32(&dev_if->out_ep_regs[i]->doepint, 0xFF); + } + + if (core_if->en_multiple_tx_fifo && core_if->dma_enable) { + dev_if->non_iso_tx_thr_en = params->thr_ctl & 0x1; + dev_if->iso_tx_thr_en = (params->thr_ctl >> 1) & 0x1; + dev_if->rx_thr_en = (params->thr_ctl >> 2) & 0x1; + + dev_if->rx_thr_length = params->rx_thr_length; + dev_if->tx_thr_length = params->tx_thr_length; + + dev_if->setup_desc_index = 0; + + dthrctl.d32 = 0; + dthrctl.b.non_iso_thr_en = dev_if->non_iso_tx_thr_en; + dthrctl.b.iso_thr_en = dev_if->iso_tx_thr_en; + dthrctl.b.tx_thr_len = dev_if->tx_thr_length; + dthrctl.b.rx_thr_en = dev_if->rx_thr_en; + dthrctl.b.rx_thr_len = dev_if->rx_thr_length; + dthrctl.b.ahb_thr_ratio = params->ahb_thr_ratio; + + dwc_write_reg32(&dev_if->dev_global_regs->dtknqr3_dthrctl, + dthrctl.d32); + + DWC_DEBUGPL(DBG_CIL, + "Non ISO Tx Thr - %d\nISO Tx Thr - %d\nRx Thr - %d\nTx Thr Len - %d\nRx Thr Len - %d\n", + dthrctl.b.non_iso_thr_en, dthrctl.b.iso_thr_en, + dthrctl.b.rx_thr_en, dthrctl.b.tx_thr_len, + dthrctl.b.rx_thr_len); + + } + + dwc_otg_enable_device_interrupts(core_if); + + { + diepmsk_data_t msk = {.d32 = 0 }; + msk.b.txfifoundrn = 1; + if (core_if->multiproc_int_enable) { + dwc_modify_reg32(&dev_if->dev_global_regs-> + diepeachintmsk[0], msk.d32, msk.d32); + } else { + dwc_modify_reg32(&dev_if->dev_global_regs->diepmsk, + msk.d32, msk.d32); + } + } + + if (core_if->multiproc_int_enable) { + /* Set NAK on Babble */ + dctl_data_t dctl = {.d32 = 0 }; + dctl.b.nakonbble = 1; + dwc_modify_reg32(&dev_if->dev_global_regs->dctl, 0, dctl.d32); + } +} + +/** + * This function enables the Host mode interrupts. + * + * @param core_if Programming view of DWC_otg controller + */ +void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * core_if) +{ + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; + gintmsk_data_t intr_mask = {.d32 = 0 }; + + DWC_DEBUGPL(DBG_CIL, "%s(%p)\n", __func__, core_if); + + /* Disable all interrupts. */ + dwc_write_reg32(&global_regs->gintmsk, 0); + + /* Clear any pending interrupts. */ + dwc_write_reg32(&global_regs->gintsts, 0xFFFFFFFF); + + /* Enable the common interrupts */ + dwc_otg_enable_common_interrupts(core_if); + + /* + * Enable host mode interrupts without disturbing common + * interrupts. + */ + + /* Do not need sof interrupt for Descriptor DMA*/ + if (!core_if->dma_desc_enable) + intr_mask.b.sofintr = 1; + intr_mask.b.portintr = 1; + intr_mask.b.hcintr = 1; + + dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32); +} + +/** + * This function disables the Host Mode interrupts. + * + * @param core_if Programming view of DWC_otg controller + */ +void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * core_if) +{ + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; + gintmsk_data_t intr_mask = {.d32 = 0 }; + + DWC_DEBUGPL(DBG_CILV, "%s()\n", __func__); + + /* + * Disable host mode interrupts without disturbing common + * interrupts. + */ + intr_mask.b.sofintr = 1; + intr_mask.b.portintr = 1; + intr_mask.b.hcintr = 1; + intr_mask.b.ptxfempty = 1; + intr_mask.b.nptxfempty = 1; + + dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, 0); +} + +/** + * This function initializes the DWC_otg controller registers for + * host mode. + * + * This function flushes the Tx and Rx FIFOs and it flushes any entries in the + * request queues. Host channels are reset to ensure that they are ready for + * performing transfers. + * + * @param core_if Programming view of DWC_otg controller + * + */ +void dwc_otg_core_host_init(dwc_otg_core_if_t * core_if) +{ + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; + dwc_otg_host_if_t *host_if = core_if->host_if; + dwc_otg_core_params_t *params = core_if->core_params; + hprt0_data_t hprt0 = {.d32 = 0 }; + fifosize_data_t nptxfifosize; + fifosize_data_t ptxfifosize; + int i; + hcchar_data_t hcchar; + hcfg_data_t hcfg; + dwc_otg_hc_regs_t *hc_regs; + int num_channels; + gotgctl_data_t gotgctl = {.d32 = 0 }; + + DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if); + + /* Restart the Phy Clock */ + dwc_write_reg32(core_if->pcgcctl, 0); + + /* Initialize Host Configuration Register */ + init_fslspclksel(core_if); + if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) { + hcfg.d32 = dwc_read_reg32(&host_if->host_global_regs->hcfg); + hcfg.b.fslssupp = 1; + dwc_write_reg32(&host_if->host_global_regs->hcfg, hcfg.d32); + + } + + if (core_if->core_params->dma_desc_enable) { + uint8_t op_mode = core_if->hwcfg2.b.op_mode; + if (!(core_if->hwcfg4.b.desc_dma && (core_if->snpsid >= OTG_CORE_REV_2_90a) && + ((op_mode == DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) || + (op_mode == DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG) || + (op_mode == DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG) || + (op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST) || + (op_mode == DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST)))) { + + DWC_ERROR("Host can't operate in Descriptor DMA mode.\n" + "Either core version is below 2.90a or " + "GHWCFG2, GHWCFG4 registers' values do not allow Descriptor DMA in host mode.\n" + "To run the driver in Buffer DMA host mode set dma_desc_enable " + "module parameter to 0.\n"); + return; + } + hcfg.d32 = dwc_read_reg32(&host_if->host_global_regs->hcfg); + hcfg.b.descdma = 1; + dwc_write_reg32(&host_if->host_global_regs->hcfg, hcfg.d32); + } + + /* Configure data FIFO sizes */ + if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) { + DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n", + core_if->total_fifo_size); + DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n", + params->host_rx_fifo_size); + DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n", + params->host_nperio_tx_fifo_size); + DWC_DEBUGPL(DBG_CIL, "P Tx FIFO Size=%d\n", + params->host_perio_tx_fifo_size); + + /* Rx FIFO */ + DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n", + dwc_read_reg32(&global_regs->grxfsiz)); + dwc_write_reg32(&global_regs->grxfsiz, + params->host_rx_fifo_size); + DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n", + dwc_read_reg32(&global_regs->grxfsiz)); + + /* Non-periodic Tx FIFO */ + DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n", + dwc_read_reg32(&global_regs->gnptxfsiz)); + nptxfifosize.b.depth = params->host_nperio_tx_fifo_size; + nptxfifosize.b.startaddr = params->host_rx_fifo_size; + dwc_write_reg32(&global_regs->gnptxfsiz, nptxfifosize.d32); + DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n", + dwc_read_reg32(&global_regs->gnptxfsiz)); + + /* Periodic Tx FIFO */ + DWC_DEBUGPL(DBG_CIL, "initial hptxfsiz=%08x\n", + dwc_read_reg32(&global_regs->hptxfsiz)); + ptxfifosize.b.depth = params->host_perio_tx_fifo_size; + ptxfifosize.b.startaddr = + nptxfifosize.b.startaddr + nptxfifosize.b.depth; + dwc_write_reg32(&global_regs->hptxfsiz, ptxfifosize.d32); + DWC_DEBUGPL(DBG_CIL, "new hptxfsiz=%08x\n", + dwc_read_reg32(&global_regs->hptxfsiz)); + } + + /* Clear Host Set HNP Enable in the OTG Control Register */ + gotgctl.b.hstsethnpen = 1; + dwc_modify_reg32(&global_regs->gotgctl, gotgctl.d32, 0); + + /* Make sure the FIFOs are flushed. */ + dwc_otg_flush_tx_fifo(core_if, 0x10 /* all Tx FIFOs */ ); + dwc_otg_flush_rx_fifo(core_if); + + if(!core_if->core_params->dma_desc_enable) { + /* Flush out any leftover queued requests. */ + num_channels = core_if->core_params->host_channels; + + for (i = 0; i < num_channels; i++) { + hc_regs = core_if->host_if->hc_regs[i]; + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + hcchar.b.chen = 0; + hcchar.b.chdis = 1; + hcchar.b.epdir = 0; + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); + } + + /* Halt all channels to put them into a known state. */ + for (i = 0; i < num_channels; i++) { + int count = 0; + hc_regs = core_if->host_if->hc_regs[i]; + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + hcchar.b.chen = 1; + hcchar.b.chdis = 1; + hcchar.b.epdir = 0; + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); + DWC_DEBUGPL(DBG_HCDV, "%s: Halt channel %d regs %p\n", __func__, i, hc_regs); + do { + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + if (++count > 1000) { + DWC_ERROR + ("%s: Unable to clear halt on channel %d (timeout HCCHAR 0x%X @%p)\n", + __func__, i, hcchar.d32, &hc_regs->hcchar); + break; + } + dwc_udelay(1); + } while (hcchar.b.chen); + } + } + + /* Turn on the vbus power. */ + DWC_PRINTF("Init: Port Power? op_state=%d\n", core_if->op_state); + if (core_if->op_state == A_HOST) { + hprt0.d32 = dwc_otg_read_hprt0(core_if); + DWC_PRINTF("Init: Power Port (%d)\n", hprt0.b.prtpwr); + if (hprt0.b.prtpwr == 0) { + hprt0.b.prtpwr = 1; + dwc_write_reg32(host_if->hprt0, hprt0.d32); + } + } + + dwc_otg_enable_host_interrupts(core_if); +} + +/** + * Prepares a host channel for transferring packets to/from a specific + * endpoint. The HCCHARn register is set up with the characteristics specified + * in _hc. Host channel interrupts that may need to be serviced while this + * transfer is in progress are enabled. + * + * @param core_if Programming view of DWC_otg controller + * @param hc Information needed to initialize the host channel + */ +void dwc_otg_hc_init(dwc_otg_core_if_t * core_if, dwc_hc_t * hc) +{ + uint32_t intr_enable; + hcintmsk_data_t hc_intr_mask; + gintmsk_data_t gintmsk = {.d32 = 0 }; + hcchar_data_t hcchar; + hcsplt_data_t hcsplt; + + uint8_t hc_num = hc->hc_num; + dwc_otg_host_if_t *host_if = core_if->host_if; + dwc_otg_hc_regs_t *hc_regs = host_if->hc_regs[hc_num]; + + /* Clear old interrupt conditions for this host channel. */ + hc_intr_mask.d32 = 0xFFFFFFFF; + hc_intr_mask.b.reserved14_31 = 0; + dwc_write_reg32(&hc_regs->hcint, hc_intr_mask.d32); + + /* Enable channel interrupts required for this transfer. */ + hc_intr_mask.d32 = 0; + hc_intr_mask.b.chhltd = 1; + if (core_if->dma_enable) { + /* For Descriptor DMA mode core halts the channel on AHB error. Interrupt is not required */ + if (!core_if->dma_desc_enable) + hc_intr_mask.b.ahberr = 1; + else { + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) + hc_intr_mask.b.xfercompl = 1; + } + + if (hc->error_state && !hc->do_split && + hc->ep_type != DWC_OTG_EP_TYPE_ISOC) { + hc_intr_mask.b.ack = 1; + if (hc->ep_is_in) { + hc_intr_mask.b.datatglerr = 1; + if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) { + hc_intr_mask.b.nak = 1; + } + } + } + } else { + switch (hc->ep_type) { + case DWC_OTG_EP_TYPE_CONTROL: + case DWC_OTG_EP_TYPE_BULK: + hc_intr_mask.b.xfercompl = 1; + hc_intr_mask.b.stall = 1; + hc_intr_mask.b.xacterr = 1; + hc_intr_mask.b.datatglerr = 1; + if (hc->ep_is_in) { + hc_intr_mask.b.bblerr = 1; + } else { + hc_intr_mask.b.nak = 1; + hc_intr_mask.b.nyet = 1; + if (hc->do_ping) { + hc_intr_mask.b.ack = 1; + } + } + + if (hc->do_split) { + hc_intr_mask.b.nak = 1; + if (hc->complete_split) { + hc_intr_mask.b.nyet = 1; + } else { + hc_intr_mask.b.ack = 1; + } + } + + if (hc->error_state) { + hc_intr_mask.b.ack = 1; + } + break; + case DWC_OTG_EP_TYPE_INTR: + hc_intr_mask.b.xfercompl = 1; + hc_intr_mask.b.nak = 1; + hc_intr_mask.b.stall = 1; + hc_intr_mask.b.xacterr = 1; + hc_intr_mask.b.datatglerr = 1; + hc_intr_mask.b.frmovrun = 1; + + if (hc->ep_is_in) { + hc_intr_mask.b.bblerr = 1; + } + if (hc->error_state) { + hc_intr_mask.b.ack = 1; + } + if (hc->do_split) { + if (hc->complete_split) { + hc_intr_mask.b.nyet = 1; + } else { + hc_intr_mask.b.ack = 1; + } + } + break; + case DWC_OTG_EP_TYPE_ISOC: + hc_intr_mask.b.xfercompl = 1; + hc_intr_mask.b.frmovrun = 1; + hc_intr_mask.b.ack = 1; + + if (hc->ep_is_in) { + hc_intr_mask.b.xacterr = 1; + hc_intr_mask.b.bblerr = 1; + } + break; + } + } + dwc_write_reg32(&hc_regs->hcintmsk, hc_intr_mask.d32); + + /* Enable the top level host channel interrupt. */ + intr_enable = (1 << hc_num); + dwc_modify_reg32(&host_if->host_global_regs->haintmsk, 0, intr_enable); + + /* Make sure host channel interrupts are enabled. */ + gintmsk.b.hcintr = 1; + dwc_modify_reg32(&core_if->core_global_regs->gintmsk, 0, gintmsk.d32); + + /* + * Program the HCCHARn register with the endpoint characteristics for + * the current transfer. + */ + hcchar.d32 = 0; + hcchar.b.devaddr = hc->dev_addr; + hcchar.b.epnum = hc->ep_num; + hcchar.b.epdir = hc->ep_is_in; + hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW); + hcchar.b.eptype = hc->ep_type; + hcchar.b.mps = hc->max_packet; + + dwc_write_reg32(&host_if->hc_regs[hc_num]->hcchar, hcchar.d32); + + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num); + DWC_DEBUGPL(DBG_HCDV, " Dev Addr: %d\n", hcchar.b.devaddr); + DWC_DEBUGPL(DBG_HCDV, " Ep Num: %d\n", hcchar.b.epnum); + DWC_DEBUGPL(DBG_HCDV, " Is In: %d\n", hcchar.b.epdir); + DWC_DEBUGPL(DBG_HCDV, " Is Low Speed: %d\n", hcchar.b.lspddev); + DWC_DEBUGPL(DBG_HCDV, " Ep Type: %d\n", hcchar.b.eptype); + DWC_DEBUGPL(DBG_HCDV, " Max Pkt: %d\n", hcchar.b.mps); + DWC_DEBUGPL(DBG_HCDV, " Multi Cnt: %d\n", hcchar.b.multicnt); + + /* + * Program the HCSPLIT register for SPLITs + */ + hcsplt.d32 = 0; + if (hc->do_split) { + DWC_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n", + hc->hc_num, + hc->complete_split ? "CSPLIT" : "SSPLIT"); + hcsplt.b.compsplt = hc->complete_split; + hcsplt.b.xactpos = hc->xact_pos; + hcsplt.b.hubaddr = hc->hub_addr; + hcsplt.b.prtaddr = hc->port_addr; + DWC_DEBUGPL(DBG_HCDV, " comp split %d\n", hc->complete_split); + DWC_DEBUGPL(DBG_HCDV, " xact pos %d\n", hc->xact_pos); + DWC_DEBUGPL(DBG_HCDV, " hub addr %d\n", hc->hub_addr); + DWC_DEBUGPL(DBG_HCDV, " port addr %d\n", hc->port_addr); + DWC_DEBUGPL(DBG_HCDV, " is_in %d\n", hc->ep_is_in); + DWC_DEBUGPL(DBG_HCDV, " Max Pkt: %d\n", hcchar.b.mps); + DWC_DEBUGPL(DBG_HCDV, " xferlen: %d\n", hc->xfer_len); + } + dwc_write_reg32(&host_if->hc_regs[hc_num]->hcsplt, hcsplt.d32); + +} + +/** + * Attempts to halt a host channel. This function should only be called in + * Slave mode or to abort a transfer in either Slave mode or DMA mode. Under + * normal circumstances in DMA mode, the controller halts the channel when the + * transfer is complete or a condition occurs that requires application + * intervention. + * + * In slave mode, checks for a free request queue entry, then sets the Channel + * Enable and Channel Disable bits of the Host Channel Characteristics + * register of the specified channel to intiate the halt. If there is no free + * request queue entry, sets only the Channel Disable bit of the HCCHARn + * register to flush requests for this channel. In the latter case, sets a + * flag to indicate that the host channel needs to be halted when a request + * queue slot is open. + * + * In DMA mode, always sets the Channel Enable and Channel Disable bits of the + * HCCHARn register. The controller ensures there is space in the request + * queue before submitting the halt request. + * + * Some time may elapse before the core flushes any posted requests for this + * host channel and halts. The Channel Halted interrupt handler completes the + * deactivation of the host channel. + * + * @param core_if Controller register interface. + * @param hc Host channel to halt. + * @param halt_status Reason for halting the channel. + */ +void dwc_otg_hc_halt(dwc_otg_core_if_t * core_if, + dwc_hc_t * hc, dwc_otg_halt_status_e halt_status) +{ + gnptxsts_data_t nptxsts; + hptxsts_data_t hptxsts; + hcchar_data_t hcchar; + dwc_otg_hc_regs_t *hc_regs; + dwc_otg_core_global_regs_t *global_regs; + dwc_otg_host_global_regs_t *host_global_regs; + + DWC_DEBUGPL(DBG_HW2937, " dwc_otg_hc_halt(%d)\n", hc->hc_num); + hc_regs = core_if->host_if->hc_regs[hc->hc_num]; + global_regs = core_if->core_global_regs; + host_global_regs = core_if->host_if->host_global_regs; + + DWC_ASSERT(!(halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS), + "halt_status = %d\n", halt_status); + + if (halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE || + halt_status == DWC_OTG_HC_XFER_AHB_ERR) { + /* + * Disable all channel interrupts except Ch Halted. The QTD + * and QH state associated with this transfer has been cleared + * (in the case of URB_DEQUEUE), so the channel needs to be + * shut down carefully to prevent crashes. + */ + hcintmsk_data_t hcintmsk; + hcintmsk.d32 = 0; + hcintmsk.b.chhltd = 1; + dwc_write_reg32(&hc_regs->hcintmsk, hcintmsk.d32); + + /* + * Make sure no other interrupts besides halt are currently + * pending. Handling another interrupt could cause a crash due + * to the QTD and QH state. + */ + dwc_write_reg32(&hc_regs->hcint, ~hcintmsk.d32); + + /* + * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR + * even if the channel was already halted for some other + * reason. + */ + hc->halt_status = halt_status; + + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + if (hcchar.b.chen == 0) { + /* + * The channel is either already halted or it hasn't + * started yet. In DMA mode, the transfer may halt if + * it finishes normally or a condition occurs that + * requires driver intervention. Don't want to halt + * the channel again. In either Slave or DMA mode, + * it's possible that the transfer has been assigned + * to a channel, but not started yet when an URB is + * dequeued. Don't want to halt a channel that hasn't + * started yet. + */ + return; + } + } + if (hc->halt_pending) { + /* + * A halt has already been issued for this channel. This might + * happen when a transfer is aborted by a higher level in + * the stack. + */ +#ifdef DEBUG + DWC_PRINTF + ("*** %s: Channel %d, _hc->halt_pending already set ***\n", + __func__, hc->hc_num); + +#endif + return; + } + + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + + /* No need to set the bit in DDMA for disabling the channel */ + //TODO check it everywhere channel is disabled + if(!core_if->core_params->dma_desc_enable) + hcchar.b.chen = 1; + hcchar.b.chdis = 1; + + if (!core_if->dma_enable) { + /* Check for space in the request queue to issue the halt. */ + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL || + hc->ep_type == DWC_OTG_EP_TYPE_BULK) { + nptxsts.d32 = dwc_read_reg32(&global_regs->gnptxsts); + if (nptxsts.b.nptxqspcavail == 0) { + hcchar.b.chen = 0; + } + } else { + hptxsts.d32 = + dwc_read_reg32(&host_global_regs->hptxsts); + if ((hptxsts.b.ptxqspcavail == 0) + || (core_if->queuing_high_bandwidth)) { + hcchar.b.chen = 0; + } + } + } + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); + + hc->halt_status = halt_status; + + if (hcchar.b.chen) { + hc->halt_pending = 1; + hc->halt_on_queue = 0; + } else { + hc->halt_on_queue = 1; + } + + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num); + DWC_DEBUGPL(DBG_HCDV, " hcchar: 0x%08x\n", hcchar.d32); + DWC_DEBUGPL(DBG_HCDV, " halt_pending: %d\n", hc->halt_pending); + DWC_DEBUGPL(DBG_HCDV, " halt_on_queue: %d\n", hc->halt_on_queue); + DWC_DEBUGPL(DBG_HCDV, " halt_status: %d\n", hc->halt_status); + + return; +} + +/** + * Clears the transfer state for a host channel. This function is normally + * called after a transfer is done and the host channel is being released. + * + * @param core_if Programming view of DWC_otg controller. + * @param hc Identifies the host channel to clean up. + */ +void dwc_otg_hc_cleanup(dwc_otg_core_if_t * core_if, dwc_hc_t * hc) +{ + dwc_otg_hc_regs_t *hc_regs; + + hc->xfer_started = 0; + + /* + * Clear channel interrupt enables and any unhandled channel interrupt + * conditions. + */ + hc_regs = core_if->host_if->hc_regs[hc->hc_num]; + dwc_write_reg32(&hc_regs->hcintmsk, 0); + dwc_write_reg32(&hc_regs->hcint, 0xFFFFFFFF); +#ifdef DEBUG + DWC_TIMER_CANCEL(core_if->hc_xfer_timer[hc->hc_num]); +#endif +} + +/** + * Sets the channel property that indicates in which frame a periodic transfer + * should occur. This is always set to the _next_ frame. This function has no + * effect on non-periodic transfers. + * + * @param core_if Programming view of DWC_otg controller. + * @param hc Identifies the host channel to set up and its properties. + * @param hcchar Current value of the HCCHAR register for the specified host + * channel. + */ +static inline void hc_set_even_odd_frame(dwc_otg_core_if_t * core_if, + dwc_hc_t * hc, hcchar_data_t * hcchar) +{ + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR || + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { + hfnum_data_t hfnum; + hfnum.d32 = + dwc_read_reg32(&core_if->host_if->host_global_regs->hfnum); + + /* 1 if _next_ frame is odd, 0 if it's even */ + hcchar->b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1; +#ifdef DEBUG + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR && hc->do_split + && !hc->complete_split) { + switch (hfnum.b.frnum & 0x7) { + case 7: + core_if->hfnum_7_samples++; + core_if->hfnum_7_frrem_accum += hfnum.b.frrem; + break; + case 0: + core_if->hfnum_0_samples++; + core_if->hfnum_0_frrem_accum += hfnum.b.frrem; + break; + default: + core_if->hfnum_other_samples++; + core_if->hfnum_other_frrem_accum += + hfnum.b.frrem; + break; + } + } +#endif + } +} + +#ifdef DEBUG +void hc_xfer_timeout(void *ptr) +{ + hc_xfer_info_t *xfer_info = (hc_xfer_info_t *) ptr; + int hc_num = xfer_info->hc->hc_num; + DWC_WARN("%s: timeout on channel %d\n", __func__, hc_num); + DWC_WARN(" start_hcchar_val 0x%08x\n", + xfer_info->core_if->start_hcchar_val[hc_num]); +} +#endif + +void set_pid_isoc(dwc_hc_t * hc) +{ + /* Set up the initial PID for the transfer. */ + if (hc->speed == DWC_OTG_EP_SPEED_HIGH) { + if (hc->ep_is_in) { + if (hc->multi_count == 1) { + hc->data_pid_start = + DWC_OTG_HC_PID_DATA0; + } else if (hc->multi_count == 2) { + hc->data_pid_start = + DWC_OTG_HC_PID_DATA1; + } else { + hc->data_pid_start = + DWC_OTG_HC_PID_DATA2; + } + } else { + if (hc->multi_count == 1) { + hc->data_pid_start = + DWC_OTG_HC_PID_DATA0; + } else { + hc->data_pid_start = + DWC_OTG_HC_PID_MDATA; + } + } + } else { + hc->data_pid_start = DWC_OTG_HC_PID_DATA0; + } +} + +/** + * This function does the setup for a data transfer for a host channel and + * starts the transfer. May be called in either Slave mode or DMA mode. In + * Slave mode, the caller must ensure that there is sufficient space in the + * request queue and Tx Data FIFO. + * + * For an OUT transfer in Slave mode, it loads a data packet into the + * appropriate FIFO. If necessary, additional data packets will be loaded in + * the Host ISR. + * + * For an IN transfer in Slave mode, a data packet is requested. The data + * packets are unloaded from the Rx FIFO in the Host ISR. If necessary, + * additional data packets are requested in the Host ISR. + * + * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ + * register along with a packet count of 1 and the channel is enabled. This + * causes a single PING transaction to occur. Other fields in HCTSIZ are + * simply set to 0 since no data transfer occurs in this case. + * + * For a PING transfer in DMA mode, the HCTSIZ register is initialized with + * all the information required to perform the subsequent data transfer. In + * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the + * controller performs the entire PING protocol, then starts the data + * transfer. + * + * @param core_if Programming view of DWC_otg controller. + * @param hc Information needed to initialize the host channel. The xfer_len + * value may be reduced to accommodate the max widths of the XferSize and + * PktCnt fields in the HCTSIZn register. The multi_count value may be changed + * to reflect the final xfer_len value. + */ +void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc) +{ + hcchar_data_t hcchar; + hctsiz_data_t hctsiz; + uint16_t num_packets; + uint32_t max_hc_xfer_size = core_if->core_params->max_transfer_size; + uint16_t max_hc_pkt_count = core_if->core_params->max_packet_count; + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num]; + + hctsiz.d32 = 0; + + if (hc->do_ping) { + if (!core_if->dma_enable) { + dwc_otg_hc_do_ping(core_if, hc); + hc->xfer_started = 1; + return; + } else { + hctsiz.b.dopng = 1; + } + } + + if (hc->do_split) { + num_packets = 1; + + if (hc->complete_split && !hc->ep_is_in) { + /* For CSPLIT OUT Transfer, set the size to 0 so the + * core doesn't expect any data written to the FIFO */ + hc->xfer_len = 0; + } else if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) { + hc->xfer_len = hc->max_packet; + } else if (!hc->ep_is_in && (hc->xfer_len > 188)) { + hc->xfer_len = 188; + } + + hctsiz.b.xfersize = hc->xfer_len; + } else { + /* + * Ensure that the transfer length and packet count will fit + * in the widths allocated for them in the HCTSIZn register. + */ + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR || + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { + /* + * Make sure the transfer size is no larger than one + * (micro)frame's worth of data. (A check was done + * when the periodic transfer was accepted to ensure + * that a (micro)frame's worth of data can be + * programmed into a channel.) + */ + uint32_t max_periodic_len = + hc->multi_count * hc->max_packet; + if (hc->xfer_len > max_periodic_len) { + hc->xfer_len = max_periodic_len; + } else { + } + } else if (hc->xfer_len > max_hc_xfer_size) { + /* Make sure that xfer_len is a multiple of max packet size. */ + hc->xfer_len = max_hc_xfer_size - hc->max_packet + 1; + } + + if (hc->xfer_len > 0) { + num_packets = + (hc->xfer_len + hc->max_packet - + 1) / hc->max_packet; + if (num_packets > max_hc_pkt_count) { + num_packets = max_hc_pkt_count; + hc->xfer_len = num_packets * hc->max_packet; + } + } else { + /* Need 1 packet for transfer length of 0. */ + num_packets = 1; + } + + if (hc->ep_is_in) { + /* Always program an integral # of max packets for IN transfers. */ + hc->xfer_len = num_packets * hc->max_packet; + } + + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR || + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { + /* + * Make sure that the multi_count field matches the + * actual transfer length. + */ + hc->multi_count = num_packets; + } + + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) + set_pid_isoc(hc); + + hctsiz.b.xfersize = hc->xfer_len; + } + + hc->start_pkt_count = num_packets; + hctsiz.b.pktcnt = num_packets; + hctsiz.b.pid = hc->data_pid_start; + dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); + + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num); + DWC_DEBUGPL(DBG_HCDV, " Xfer Size: %d\n", hctsiz.b.xfersize); + DWC_DEBUGPL(DBG_HCDV, " Num Pkts: %d\n", hctsiz.b.pktcnt); + DWC_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid); + + if (core_if->dma_enable) { + dwc_dma_t dma_addr; + if (hc->align_buff) { + dma_addr = hc->align_buff; + } else { + dma_addr = (uint32_t)hc->xfer_buff; + } + dwc_write_reg32(&hc_regs->hcdma, dma_addr); + } + + /* Start the split */ + if (hc->do_split) { + hcsplt_data_t hcsplt; + hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt); + hcsplt.b.spltena = 1; + dwc_write_reg32(&hc_regs->hcsplt, hcsplt.d32); + } + + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + hcchar.b.multicnt = hc->multi_count; + hc_set_even_odd_frame(core_if, hc, &hcchar); +#ifdef DEBUG + core_if->start_hcchar_val[hc->hc_num] = hcchar.d32; + if (hcchar.b.chdis) { + DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n", + __func__, hc->hc_num, hcchar.d32); + } +#endif + + /* Set host channel enable after all other setup is complete. */ + hcchar.b.chen = 1; + hcchar.b.chdis = 0; + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); + + hc->xfer_started = 1; + hc->requests++; + + if (!core_if->dma_enable && !hc->ep_is_in && hc->xfer_len > 0) { + /* Load OUT packet into the appropriate Tx FIFO. */ + dwc_otg_hc_write_packet(core_if, hc); + } +#ifdef DEBUG + if (hc->ep_type != DWC_OTG_EP_TYPE_INTR) { + DWC_DEBUGPL(DBG_HCDV, "transfer %d from core_if %p\n", + hc->hc_num, core_if);//GRAYG + core_if->hc_xfer_info[hc->hc_num].core_if = core_if; + core_if->hc_xfer_info[hc->hc_num].hc = hc; + /* Start a timer for this transfer. */ + DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000); + } +#endif +} + +/** + * This function does the setup for a data transfer for a host channel + * and starts the transfer in Descriptor DMA mode. + * + * Initializes HCTSIZ register. For a PING transfer the Do Ping bit is set. + * Sets PID and NTD values. For periodic transfers + * initializes SCHED_INFO field with micro-frame bitmap. + * + * Initializes HCDMA register with descriptor list address and CTD value + * then starts the transfer via enabling the channel. + * + * @param core_if Programming view of DWC_otg controller. + * @param hc Information needed to initialize the host channel. + */ +void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if, dwc_hc_t * hc) +{ + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num]; + hcchar_data_t hcchar; + hctsiz_data_t hctsiz; + hcdma_data_t hcdma; + + hctsiz.d32 = 0; + + if (hc->do_ping && !hc->ep_is_in) + hctsiz.b_ddma.dopng = 1; + + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) + set_pid_isoc(hc); + + /* Packet Count and Xfer Size are not used in Descriptor DMA mode */ + hctsiz.b_ddma.pid = hc->data_pid_start; + hctsiz.b_ddma.ntd = hc->ntd - 1; /* 0 - 1 descriptor, 1 - 2 descriptors, etc. */ + hctsiz.b_ddma.schinfo = hc->schinfo; /* Non-zero only for high-speed interrupt endpoints */ + + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num); + DWC_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid); + DWC_DEBUGPL(DBG_HCDV, " NTD: %d\n", hctsiz.b_ddma.ntd); + + dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); + + hcdma.d32 = 0; + hcdma.b.dma_addr = ((uint32_t)hc->desc_list_addr) >> 11; + + /* Always start from first descriptor. */ + hcdma.b.ctd = 0; + dwc_write_reg32(&hc_regs->hcdma, hcdma.d32); + + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + hcchar.b.multicnt = hc->multi_count; + +#ifdef DEBUG + core_if->start_hcchar_val[hc->hc_num] = hcchar.d32; + if (hcchar.b.chdis) { + DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n", + __func__, hc->hc_num, hcchar.d32); + } +#endif + + /* Set host channel enable after all other setup is complete. */ + hcchar.b.chen = 1; + hcchar.b.chdis = 0; + + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); + + hc->xfer_started = 1; + hc->requests++; + +#ifdef DEBUG + if ((hc->ep_type != DWC_OTG_EP_TYPE_INTR) && (hc->ep_type != DWC_OTG_EP_TYPE_ISOC)) { + DWC_DEBUGPL(DBG_HCDV, "DMA transfer %d from core_if %p\n", + hc->hc_num, core_if);//GRAYG + core_if->hc_xfer_info[hc->hc_num].core_if = core_if; + core_if->hc_xfer_info[hc->hc_num].hc = hc; + /* Start a timer for this transfer. */ + DWC_TIMER_SCHEDULE(core_if->hc_xfer_timer[hc->hc_num], 10000); + } + +#endif + +} + +/** + * This function continues a data transfer that was started by previous call + * to dwc_otg_hc_start_transfer. The caller must ensure there is + * sufficient space in the request queue and Tx Data FIFO. This function + * should only be called in Slave mode. In DMA mode, the controller acts + * autonomously to complete transfers programmed to a host channel. + * + * For an OUT transfer, a new data packet is loaded into the appropriate FIFO + * if there is any data remaining to be queued. For an IN transfer, another + * data packet is always requested. For the SETUP phase of a control transfer, + * this function does nothing. + * + * @return 1 if a new request is queued, 0 if no more requests are required + * for this transfer. + */ +int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * core_if, dwc_hc_t * hc) +{ + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num); + + if (hc->do_split) { + /* SPLITs always queue just once per channel */ + return 0; + } else if (hc->data_pid_start == DWC_OTG_HC_PID_SETUP) { + /* SETUPs are queued only once since they can't be NAKed. */ + return 0; + } else if (hc->ep_is_in) { + /* + * Always queue another request for other IN transfers. If + * back-to-back INs are issued and NAKs are received for both, + * the driver may still be processing the first NAK when the + * second NAK is received. When the interrupt handler clears + * the NAK interrupt for the first NAK, the second NAK will + * not be seen. So we can't depend on the NAK interrupt + * handler to requeue a NAKed request. Instead, IN requests + * are issued each time this function is called. When the + * transfer completes, the extra requests for the channel will + * be flushed. + */ + hcchar_data_t hcchar; + dwc_otg_hc_regs_t *hc_regs = + core_if->host_if->hc_regs[hc->hc_num]; + + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + hc_set_even_odd_frame(core_if, hc, &hcchar); + hcchar.b.chen = 1; + hcchar.b.chdis = 0; + DWC_DEBUGPL(DBG_HCDV, " IN xfer: hcchar = 0x%08x\n", + hcchar.d32); + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); + hc->requests++; + return 1; + } else { + /* OUT transfers. */ + if (hc->xfer_count < hc->xfer_len) { + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR || + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { + hcchar_data_t hcchar; + dwc_otg_hc_regs_t *hc_regs; + hc_regs = core_if->host_if->hc_regs[hc->hc_num]; + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + hc_set_even_odd_frame(core_if, hc, &hcchar); + } + + /* Load OUT packet into the appropriate Tx FIFO. */ + dwc_otg_hc_write_packet(core_if, hc); + hc->requests++; + return 1; + } else { + return 0; + } + } +} + +/** + * Starts a PING transfer. This function should only be called in Slave mode. + * The Do Ping bit is set in the HCTSIZ register, then the channel is enabled. + */ +void dwc_otg_hc_do_ping(dwc_otg_core_if_t * core_if, dwc_hc_t * hc) +{ + hcchar_data_t hcchar; + hctsiz_data_t hctsiz; + dwc_otg_hc_regs_t *hc_regs = core_if->host_if->hc_regs[hc->hc_num]; + + DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num); + + hctsiz.d32 = 0; + hctsiz.b.dopng = 1; + hctsiz.b.pktcnt = 1; + dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); + + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + hcchar.b.chen = 1; + hcchar.b.chdis = 0; + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); +} + +/* + * This function writes a packet into the Tx FIFO associated with the Host + * Channel. For a channel associated with a non-periodic EP, the non-periodic + * Tx FIFO is written. For a channel associated with a periodic EP, the + * periodic Tx FIFO is written. This function should only be called in Slave + * mode. + * + * Upon return the xfer_buff and xfer_count fields in _hc are incremented by + * then number of bytes written to the Tx FIFO. + */ +void dwc_otg_hc_write_packet(dwc_otg_core_if_t * core_if, dwc_hc_t * hc) +{ + uint32_t i; + uint32_t remaining_count; + uint32_t byte_count; + uint32_t dword_count; + + uint32_t *data_buff = (uint32_t *) (hc->xfer_buff); + uint32_t *data_fifo = core_if->data_fifo[hc->hc_num]; + + remaining_count = hc->xfer_len - hc->xfer_count; + if (remaining_count > hc->max_packet) { + byte_count = hc->max_packet; + } else { + byte_count = remaining_count; + } + + dword_count = (byte_count + 3) / 4; + + if ((((unsigned long)data_buff) & 0x3) == 0) { + /* xfer_buff is DWORD aligned. */ + for (i = 0; i < dword_count; i++, data_buff++) { + dwc_write_reg32(data_fifo, *data_buff); + } + } else { + /* xfer_buff is not DWORD aligned. */ + for (i = 0; i < dword_count; i++, data_buff++) { + uint32_t data; + data = + (data_buff[0] | data_buff[1] << 8 | data_buff[2] << + 16 | data_buff[3] << 24); + dwc_write_reg32(data_fifo, data); + } + } + + hc->xfer_count += byte_count; + hc->xfer_buff += byte_count; +} + +/** + * Gets the current USB frame number. This is the frame number from the last + * SOF packet. + */ +uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * core_if) +{ + dsts_data_t dsts; + dsts.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts); + + /* read current frame/microframe number from DSTS register */ + return dsts.b.soffn; +} + +/** + * This function reads a setup packet from the Rx FIFO into the destination + * buffer. This function is called from the Rx Status Queue Level (RxStsQLvl) + * Interrupt routine when a SETUP packet has been received in Slave mode. + * + * @param core_if Programming view of DWC_otg controller. + * @param dest Destination buffer for packet data. + */ +void dwc_otg_read_setup_packet(dwc_otg_core_if_t * core_if, uint32_t * dest) +{ + /* Get the 8 bytes of a setup transaction data */ + + /* Pop 2 DWORDS off the receive data FIFO into memory */ + dest[0] = dwc_read_reg32(core_if->data_fifo[0]); + dest[1] = dwc_read_reg32(core_if->data_fifo[0]); +} + +/** + * This function enables EP0 OUT to receive SETUP packets and configures EP0 + * IN for transmitting packets. It is normally called when the + * "Enumeration Done" interrupt occurs. + * + * @param core_if Programming view of DWC_otg controller. + * @param ep The EP0 data. + */ +void dwc_otg_ep0_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep) +{ + dwc_otg_dev_if_t *dev_if = core_if->dev_if; + dsts_data_t dsts; + depctl_data_t diepctl; + depctl_data_t doepctl; + dctl_data_t dctl = {.d32 = 0 }; + + /* Read the Device Status and Endpoint 0 Control registers */ + dsts.d32 = dwc_read_reg32(&dev_if->dev_global_regs->dsts); + diepctl.d32 = dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl); + doepctl.d32 = dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl); + + /* Set the MPS of the IN EP based on the enumeration speed */ + switch (dsts.b.enumspd) { + case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: + case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: + case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ: + diepctl.b.mps = DWC_DEP0CTL_MPS_64; + break; + case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ: + diepctl.b.mps = DWC_DEP0CTL_MPS_8; + break; + } + + dwc_write_reg32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32); + + /* Enable OUT EP for receive */ + doepctl.b.epena = 1; + dwc_write_reg32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32); + +#ifdef VERBOSE + DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n", + dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl)); + DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n", + dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl)); +#endif + dctl.b.cgnpinnak = 1; + + dwc_modify_reg32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32); + DWC_DEBUGPL(DBG_PCDV, "dctl=%0x\n", + dwc_read_reg32(&dev_if->dev_global_regs->dctl)); +} + +/** + * This function activates an EP. The Device EP control register for + * the EP is configured as defined in the ep structure. Note: This + * function is not used for EP0. + * + * @param core_if Programming view of DWC_otg controller. + * @param ep The EP to activate. + */ +void dwc_otg_ep_activate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep) +{ + dwc_otg_dev_if_t *dev_if = core_if->dev_if; + depctl_data_t depctl; + volatile uint32_t *addr; + daint_data_t daintmsk = {.d32 = 0 }; + + DWC_DEBUGPL(DBG_PCDV, "%s() EP%d-%s\n", __func__, ep->num, + (ep->is_in ? "IN" : "OUT")); + + /* Read DEPCTLn register */ + if (ep->is_in == 1) { + addr = &dev_if->in_ep_regs[ep->num]->diepctl; + daintmsk.ep.in = 1 << ep->num; + } else { + addr = &dev_if->out_ep_regs[ep->num]->doepctl; + daintmsk.ep.out = 1 << ep->num; + } + + /* If the EP is already active don't change the EP Control + * register. */ + depctl.d32 = dwc_read_reg32(addr); + if (!depctl.b.usbactep) { + depctl.b.mps = ep->maxpacket; + depctl.b.eptype = ep->type; + depctl.b.txfnum = ep->tx_fifo_num; + + if (ep->type == DWC_OTG_EP_TYPE_ISOC) { + depctl.b.setd0pid = 1; // ??? + } else { + depctl.b.setd0pid = 1; + } + depctl.b.usbactep = 1; + + dwc_write_reg32(addr, depctl.d32); + DWC_DEBUGPL(DBG_PCDV, "DEPCTL=%08x\n", dwc_read_reg32(addr)); + } + + /* Enable the Interrupt for this EP */ + if (core_if->multiproc_int_enable) { + if (ep->is_in == 1) { + diepmsk_data_t diepmsk = {.d32 = 0 }; + diepmsk.b.xfercompl = 1; + diepmsk.b.timeout = 1; + diepmsk.b.epdisabled = 1; + diepmsk.b.ahberr = 1; + diepmsk.b.intknepmis = 1; + diepmsk.b.txfifoundrn = 1; //????? + + if (core_if->dma_desc_enable) { + diepmsk.b.bna = 1; + } +/* + if(core_if->dma_enable) { + doepmsk.b.nak = 1; + } +*/ + dwc_write_reg32(&dev_if->dev_global_regs-> + diepeachintmsk[ep->num], diepmsk.d32); + + } else { + doepmsk_data_t doepmsk = {.d32 = 0 }; + doepmsk.b.xfercompl = 1; + doepmsk.b.ahberr = 1; + doepmsk.b.epdisabled = 1; + + if (core_if->dma_desc_enable) { + doepmsk.b.bna = 1; + } +/* + doepmsk.b.babble = 1; + doepmsk.b.nyet = 1; + doepmsk.b.nak = 1; +*/ + dwc_write_reg32(&dev_if->dev_global_regs-> + doepeachintmsk[ep->num], doepmsk.d32); + } + dwc_modify_reg32(&dev_if->dev_global_regs->deachintmsk, + 0, daintmsk.d32); + } else { + dwc_modify_reg32(&dev_if->dev_global_regs->daintmsk, + 0, daintmsk.d32); + } + + DWC_DEBUGPL(DBG_PCDV, "DAINTMSK=%0x\n", + dwc_read_reg32(&dev_if->dev_global_regs->daintmsk)); + + ep->stall_clear_flag = 0; + return; +} + +/** + * This function deactivates an EP. This is done by clearing the USB Active + * EP bit in the Device EP control register. Note: This function is not used + * for EP0. EP0 cannot be deactivated. + * + * @param core_if Programming view of DWC_otg controller. + * @param ep The EP to deactivate. + */ +void dwc_otg_ep_deactivate(dwc_otg_core_if_t * core_if, dwc_ep_t * ep) +{ + depctl_data_t depctl = {.d32 = 0 }; + volatile uint32_t *addr; + daint_data_t daintmsk = {.d32 = 0 }; + + /* Read DEPCTLn register */ + if (ep->is_in == 1) { + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl; + daintmsk.ep.in = 1 << ep->num; + } else { + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl; + daintmsk.ep.out = 1 << ep->num; + } + + depctl.d32 = dwc_read_reg32(addr); + + depctl.b.usbactep = 0; + + if (core_if->dma_desc_enable) + depctl.b.epdis = 1; + + dwc_write_reg32(addr, depctl.d32); + + /* Disable the Interrupt for this EP */ + if (core_if->multiproc_int_enable) { + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->deachintmsk, + daintmsk.d32, 0); + + if (ep->is_in == 1) { + dwc_write_reg32(&core_if->dev_if->dev_global_regs-> + diepeachintmsk[ep->num], 0); + } else { + dwc_write_reg32(&core_if->dev_if->dev_global_regs-> + doepeachintmsk[ep->num], 0); + } + } else { + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->daintmsk, + daintmsk.d32, 0); + } +} + +/** + * This function initializes dma descriptor chain. + * + * @param core_if Programming view of DWC_otg controller. + * @param ep The EP to start the transfer on. + */ +static void init_dma_desc_chain(dwc_otg_core_if_t * core_if, dwc_ep_t * ep) +{ + dwc_otg_dev_dma_desc_t *dma_desc; + uint32_t offset; + uint32_t xfer_est; + int i; + + ep->desc_cnt = (ep->total_len / ep->maxxfer) + + ((ep->total_len % ep->maxxfer) ? 1 : 0); + if (!ep->desc_cnt) + ep->desc_cnt = 1; + + dma_desc = ep->desc_addr; + xfer_est = ep->total_len; + offset = 0; + for (i = 0; i < ep->desc_cnt; ++i) { + /** DMA Descriptor Setup */ + if (xfer_est > ep->maxxfer) { + dma_desc->status.b.bs = BS_HOST_BUSY; + dma_desc->status.b.l = 0; + dma_desc->status.b.ioc = 0; + dma_desc->status.b.sp = 0; + dma_desc->status.b.bytes = ep->maxxfer; + dma_desc->buf = ep->dma_addr + offset; + dma_desc->status.b.bs = BS_HOST_READY; + + xfer_est -= ep->maxxfer; + offset += ep->maxxfer; + } else { + dma_desc->status.b.bs = BS_HOST_BUSY; + dma_desc->status.b.l = 1; + dma_desc->status.b.ioc = 1; + if (ep->is_in) { + dma_desc->status.b.sp = + (xfer_est % + ep->maxpacket) ? 1 : ((ep-> + sent_zlp) ? 1 : 0); + dma_desc->status.b.bytes = xfer_est; + } else { + dma_desc->status.b.bytes = + xfer_est + ((4 - (xfer_est & 0x3)) & 0x3); + } + + dma_desc->buf = ep->dma_addr + offset; + dma_desc->status.b.bs = BS_HOST_READY; + } + dma_desc++; + } +} + +/** + * This function does the setup for a data transfer for an EP and + * starts the transfer. For an IN transfer, the packets will be + * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers, + * the packets are unloaded from the Rx FIFO in the ISR. the ISR. + * + * @param core_if Programming view of DWC_otg controller. + * @param ep The EP to start the transfer on. + */ + +void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep) +{ + depctl_data_t depctl; + deptsiz_data_t deptsiz; + gintmsk_data_t intr_mask = {.d32 = 0 }; + + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__); + DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d " + "xfer_buff=%p start_xfer_buff=%p, total_len = %d\n", + ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len, + ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff, + ep->total_len); + /* IN endpoint */ + if (ep->is_in == 1) { + dwc_otg_dev_in_ep_regs_t *in_regs = + core_if->dev_if->in_ep_regs[ep->num]; + + gnptxsts_data_t gtxstatus; + + gtxstatus.d32 = + dwc_read_reg32(&core_if->core_global_regs->gnptxsts); + + if (core_if->en_multiple_tx_fifo == 0 + && gtxstatus.b.nptxqspcavail == 0) { +#ifdef DEBUG + DWC_PRINTF("TX Queue Full (0x%0x)\n", gtxstatus.d32); +#endif + return; + } + + depctl.d32 = dwc_read_reg32(&(in_regs->diepctl)); + deptsiz.d32 = dwc_read_reg32(&(in_regs->dieptsiz)); + + ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ? + ep->maxxfer : (ep->total_len - ep->xfer_len); + + /* Zero Length Packet? */ + if ((ep->xfer_len - ep->xfer_count) == 0) { + deptsiz.b.xfersize = 0; + deptsiz.b.pktcnt = 1; + } else { + /* Program the transfer size and packet count + * as follows: xfersize = N * maxpacket + + * short_packet pktcnt = N + (short_packet + * exist ? 1 : 0) + */ + deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count; + deptsiz.b.pktcnt = + (ep->xfer_len - ep->xfer_count - 1 + + ep->maxpacket) / ep->maxpacket; + } + + /* Write the DMA register */ + if (core_if->dma_enable) { + if (core_if->dma_desc_enable == 0) { + dwc_write_reg32(&in_regs->dieptsiz, + deptsiz.d32); + dwc_write_reg32(&(in_regs->diepdma), + (uint32_t) ep->dma_addr); + } else { +#ifdef DWC_UTE_CFI + /* The descriptor chain should be already initialized by now */ + if (ep->buff_mode != BM_STANDARD) { + dwc_write_reg32(&in_regs->diepdma, + ep->descs_dma_addr); + } else { +#endif + init_dma_desc_chain(core_if, ep); + /** DIEPDMAn Register write */ + dwc_write_reg32(&in_regs->diepdma, + ep->dma_desc_addr); +#ifdef DWC_UTE_CFI + } +#endif + } + } else { + dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32); + if (ep->type != DWC_OTG_EP_TYPE_ISOC) { + /** + * Enable the Non-Periodic Tx FIFO empty interrupt, + * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode, + * the data will be written into the fifo by the ISR. + */ + if (core_if->en_multiple_tx_fifo == 0) { + intr_mask.b.nptxfempty = 1; + dwc_modify_reg32(&core_if-> + core_global_regs-> + gintmsk, intr_mask.d32, + intr_mask.d32); + } else { + /* Enable the Tx FIFO Empty Interrupt for this EP */ + if (ep->xfer_len > 0) { + uint32_t fifoemptymsk = 0; + fifoemptymsk = 1 << ep->num; + dwc_modify_reg32(&core_if-> + dev_if-> + dev_global_regs-> + dtknqr4_fifoemptymsk, + 0, + fifoemptymsk); + + } + } + } + } + + /* EP enable, IN data in FIFO */ + depctl.b.cnak = 1; + depctl.b.epena = 1; + dwc_write_reg32(&in_regs->diepctl, depctl.d32); + + depctl.d32 = + dwc_read_reg32(&core_if->dev_if->in_ep_regs[0]->diepctl); + depctl.b.nextep = ep->num; + dwc_write_reg32(&core_if->dev_if->in_ep_regs[0]->diepctl, + depctl.d32); + + } else { + /* OUT endpoint */ + dwc_otg_dev_out_ep_regs_t *out_regs = + core_if->dev_if->out_ep_regs[ep->num]; + + depctl.d32 = dwc_read_reg32(&(out_regs->doepctl)); + deptsiz.d32 = dwc_read_reg32(&(out_regs->doeptsiz)); + + ep->xfer_len += (ep->maxxfer < (ep->total_len - ep->xfer_len)) ? + ep->maxxfer : (ep->total_len - ep->xfer_len); + + /* Program the transfer size and packet count as follows: + * + * pktcnt = N + * xfersize = N * maxpacket + */ + if ((ep->xfer_len - ep->xfer_count) == 0) { + /* Zero Length Packet */ + deptsiz.b.xfersize = ep->maxpacket; + deptsiz.b.pktcnt = 1; + } else { + deptsiz.b.pktcnt = + (ep->xfer_len - ep->xfer_count + + (ep->maxpacket - 1)) / ep->maxpacket; + ep->xfer_len = + deptsiz.b.pktcnt * ep->maxpacket + ep->xfer_count; + deptsiz.b.xfersize = ep->xfer_len - ep->xfer_count; + } + + DWC_DEBUGPL(DBG_PCDV, "ep%d xfersize=%d pktcnt=%d\n", + ep->num, deptsiz.b.xfersize, deptsiz.b.pktcnt); + + if (core_if->dma_enable) { + if (!core_if->dma_desc_enable) { + dwc_write_reg32(&out_regs->doeptsiz, + deptsiz.d32); + + dwc_write_reg32(&(out_regs->doepdma), + (uint32_t) ep->dma_addr); + } else { +#ifdef DWC_UTE_CFI + /* The descriptor chain should be already initialized by now */ + if (ep->buff_mode != BM_STANDARD) { + dwc_write_reg32(&out_regs->doepdma, + ep->descs_dma_addr); + } else { +#endif + + init_dma_desc_chain(core_if, ep); + + /** DOEPDMAn Register write */ + dwc_write_reg32(&out_regs->doepdma, + ep->dma_desc_addr); +#ifdef DWC_UTE_CFI + } +#endif + } + } else { + dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32); + } + + /* EP enable */ + depctl.b.cnak = 1; + depctl.b.epena = 1; + + dwc_write_reg32(&out_regs->doepctl, depctl.d32); + + DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n", + dwc_read_reg32(&out_regs->doepctl), + dwc_read_reg32(&out_regs->doeptsiz)); + DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n", + dwc_read_reg32(&core_if->dev_if->dev_global_regs-> + daintmsk), + dwc_read_reg32(&core_if->core_global_regs-> + gintmsk)); + } +} + +/** + * This function setup a zero length transfer in Buffer DMA and + * Slave modes for usb requests with zero field set + * + * @param core_if Programming view of DWC_otg controller. + * @param ep The EP to start the transfer on. + * + */ +void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep) +{ + + depctl_data_t depctl; + deptsiz_data_t deptsiz; + gintmsk_data_t intr_mask = {.d32 = 0 }; + + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__); + DWC_PRINTF("zero length transfer is called\n"); + + /* IN endpoint */ + if (ep->is_in == 1) { + dwc_otg_dev_in_ep_regs_t *in_regs = + core_if->dev_if->in_ep_regs[ep->num]; + + depctl.d32 = dwc_read_reg32(&(in_regs->diepctl)); + deptsiz.d32 = dwc_read_reg32(&(in_regs->dieptsiz)); + + deptsiz.b.xfersize = 0; + deptsiz.b.pktcnt = 1; + + /* Write the DMA register */ + if (core_if->dma_enable) { + if (core_if->dma_desc_enable == 0) { + dwc_write_reg32(&in_regs->dieptsiz, + deptsiz.d32); + dwc_write_reg32(&(in_regs->diepdma), + (uint32_t) ep->dma_addr); + } + } else { + dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32); + /** + * Enable the Non-Periodic Tx FIFO empty interrupt, + * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode, + * the data will be written into the fifo by the ISR. + */ + if (core_if->en_multiple_tx_fifo == 0) { + intr_mask.b.nptxfempty = 1; + dwc_modify_reg32(&core_if->core_global_regs-> + gintmsk, intr_mask.d32, + intr_mask.d32); + } else { + /* Enable the Tx FIFO Empty Interrupt for this EP */ + if (ep->xfer_len > 0) { + uint32_t fifoemptymsk = 0; + fifoemptymsk = 1 << ep->num; + dwc_modify_reg32(&core_if->dev_if-> + dev_global_regs-> + dtknqr4_fifoemptymsk, + 0, fifoemptymsk); + } + } + } + + /* EP enable, IN data in FIFO */ + depctl.b.cnak = 1; + depctl.b.epena = 1; + dwc_write_reg32(&in_regs->diepctl, depctl.d32); + + depctl.d32 = + dwc_read_reg32(&core_if->dev_if->in_ep_regs[0]->diepctl); + depctl.b.nextep = ep->num; + dwc_write_reg32(&core_if->dev_if->in_ep_regs[0]->diepctl, + depctl.d32); + + } else { + /* OUT endpoint */ + dwc_otg_dev_out_ep_regs_t *out_regs = + core_if->dev_if->out_ep_regs[ep->num]; + + depctl.d32 = dwc_read_reg32(&(out_regs->doepctl)); + deptsiz.d32 = dwc_read_reg32(&(out_regs->doeptsiz)); + + /* Zero Length Packet */ + deptsiz.b.xfersize = ep->maxpacket; + deptsiz.b.pktcnt = 1; + + if (core_if->dma_enable) { + if (!core_if->dma_desc_enable) { + dwc_write_reg32(&out_regs->doeptsiz, + deptsiz.d32); + + dwc_write_reg32(&(out_regs->doepdma), + (uint32_t) ep->dma_addr); + } + } else { + dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32); + } + + /* EP enable */ + depctl.b.cnak = 1; + depctl.b.epena = 1; + + dwc_write_reg32(&out_regs->doepctl, depctl.d32); + + } +} + +/** + * This function does the setup for a data transfer for EP0 and starts + * the transfer. For an IN transfer, the packets will be loaded into + * the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are + * unloaded from the Rx FIFO in the ISR. + * + * @param core_if Programming view of DWC_otg controller. + * @param ep The EP0 data. + */ +void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep) +{ + depctl_data_t depctl; + deptsiz0_data_t deptsiz; + gintmsk_data_t intr_mask = {.d32 = 0 }; + dwc_otg_dev_dma_desc_t *dma_desc; + + DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d " + "xfer_buff=%p start_xfer_buff=%p \n", + ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len, + ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff); + + ep->total_len = ep->xfer_len; + + /* IN endpoint */ + if (ep->is_in == 1) { + dwc_otg_dev_in_ep_regs_t *in_regs = + core_if->dev_if->in_ep_regs[0]; + + gnptxsts_data_t gtxstatus; + + gtxstatus.d32 = + dwc_read_reg32(&core_if->core_global_regs->gnptxsts); + + if (core_if->en_multiple_tx_fifo == 0 + && gtxstatus.b.nptxqspcavail == 0) { +#ifdef DEBUG + deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz); + DWC_DEBUGPL(DBG_PCD, "DIEPCTL0=%0x\n", + dwc_read_reg32(&in_regs->diepctl)); + DWC_DEBUGPL(DBG_PCD, "DIEPTSIZ0=%0x (sz=%d, pcnt=%d)\n", + deptsiz.d32, + deptsiz.b.xfersize, deptsiz.b.pktcnt); + DWC_PRINTF("TX Queue or FIFO Full (0x%0x)\n", + gtxstatus.d32); +#endif + return; + } + + depctl.d32 = dwc_read_reg32(&in_regs->diepctl); + deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz); + + /* Zero Length Packet? */ + if (ep->xfer_len == 0) { + deptsiz.b.xfersize = 0; + deptsiz.b.pktcnt = 1; + } else { + /* Program the transfer size and packet count + * as follows: xfersize = N * maxpacket + + * short_packet pktcnt = N + (short_packet + * exist ? 1 : 0) + */ + if (ep->xfer_len > ep->maxpacket) { + ep->xfer_len = ep->maxpacket; + deptsiz.b.xfersize = ep->maxpacket; + } else { + deptsiz.b.xfersize = ep->xfer_len; + } + deptsiz.b.pktcnt = 1; + + } + DWC_DEBUGPL(DBG_PCDV, + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n", + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt, + deptsiz.d32); + + /* Write the DMA register */ + if (core_if->dma_enable) { + if (core_if->dma_desc_enable == 0) { + dwc_write_reg32(&in_regs->dieptsiz, + deptsiz.d32); + + dwc_write_reg32(&(in_regs->diepdma), + (uint32_t) ep->dma_addr); + } else { + dma_desc = core_if->dev_if->in_desc_addr; + + /** DMA Descriptor Setup */ + dma_desc->status.b.bs = BS_HOST_BUSY; + dma_desc->status.b.l = 1; + dma_desc->status.b.ioc = 1; + dma_desc->status.b.sp = + (ep->xfer_len == ep->maxpacket) ? 0 : 1; + dma_desc->status.b.bytes = ep->xfer_len; + dma_desc->buf = ep->dma_addr; + dma_desc->status.b.bs = BS_HOST_READY; + + /** DIEPDMA0 Register write */ + dwc_write_reg32(&in_regs->diepdma, + core_if->dev_if-> + dma_in_desc_addr); + } + } else { + dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32); + } + + /* EP enable, IN data in FIFO */ + depctl.b.cnak = 1; + depctl.b.epena = 1; + dwc_write_reg32(&in_regs->diepctl, depctl.d32); + + /** + * Enable the Non-Periodic Tx FIFO empty interrupt, the + * data will be written into the fifo by the ISR. + */ + if (!core_if->dma_enable) { + if (core_if->en_multiple_tx_fifo == 0) { + intr_mask.b.nptxfempty = 1; + dwc_modify_reg32(&core_if->core_global_regs-> + gintmsk, intr_mask.d32, + intr_mask.d32); + } else { + /* Enable the Tx FIFO Empty Interrupt for this EP */ + if (ep->xfer_len > 0) { + uint32_t fifoemptymsk = 0; + fifoemptymsk |= 1 << ep->num; + dwc_modify_reg32(&core_if->dev_if-> + dev_global_regs-> + dtknqr4_fifoemptymsk, + 0, fifoemptymsk); + } + } + } + } else { + /* OUT endpoint */ + dwc_otg_dev_out_ep_regs_t *out_regs = + core_if->dev_if->out_ep_regs[0]; + + depctl.d32 = dwc_read_reg32(&out_regs->doepctl); + deptsiz.d32 = dwc_read_reg32(&out_regs->doeptsiz); + + /* Program the transfer size and packet count as follows: + * xfersize = N * (maxpacket + 4 - (maxpacket % 4)) + * pktcnt = N */ + /* Zero Length Packet */ + deptsiz.b.xfersize = ep->maxpacket; + deptsiz.b.pktcnt = 1; + + DWC_DEBUGPL(DBG_PCDV, "len=%d xfersize=%d pktcnt=%d\n", + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt); + + if (core_if->dma_enable) { + if (!core_if->dma_desc_enable) { + dwc_write_reg32(&out_regs->doeptsiz, + deptsiz.d32); + + dwc_write_reg32(&(out_regs->doepdma), + (uint32_t) ep->dma_addr); + } else { + dma_desc = core_if->dev_if->out_desc_addr; + + /** DMA Descriptor Setup */ + dma_desc->status.b.bs = BS_HOST_BUSY; + dma_desc->status.b.l = 1; + dma_desc->status.b.ioc = 1; + dma_desc->status.b.bytes = ep->maxpacket; + dma_desc->buf = ep->dma_addr; + dma_desc->status.b.bs = BS_HOST_READY; + + /** DOEPDMA0 Register write */ + dwc_write_reg32(&out_regs->doepdma, + core_if->dev_if-> + dma_out_desc_addr); + } + } else { + dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32); + } + + /* EP enable */ + depctl.b.cnak = 1; + depctl.b.epena = 1; + dwc_write_reg32(&(out_regs->doepctl), depctl.d32); + } +} + +/** + * This function continues control IN transfers started by + * dwc_otg_ep0_start_transfer, when the transfer does not fit in a + * single packet. NOTE: The DIEPCTL0/DOEPCTL0 registers only have one + * bit for the packet count. + * + * @param core_if Programming view of DWC_otg controller. + * @param ep The EP0 data. + */ +void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep) +{ + depctl_data_t depctl; + deptsiz0_data_t deptsiz; + gintmsk_data_t intr_mask = {.d32 = 0 }; + dwc_otg_dev_dma_desc_t *dma_desc; + + if (ep->is_in == 1) { + dwc_otg_dev_in_ep_regs_t *in_regs = + core_if->dev_if->in_ep_regs[0]; + gnptxsts_data_t tx_status = {.d32 = 0 }; + + tx_status.d32 = + dwc_read_reg32(&core_if->core_global_regs->gnptxsts); + /** @todo Should there be check for room in the Tx + * Status Queue. If not remove the code above this comment. */ + + depctl.d32 = dwc_read_reg32(&in_regs->diepctl); + deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz); + + /* Program the transfer size and packet count + * as follows: xfersize = N * maxpacket + + * short_packet pktcnt = N + (short_packet + * exist ? 1 : 0) + */ + + if (core_if->dma_desc_enable == 0) { + deptsiz.b.xfersize = + (ep->total_len - ep->xfer_count) > + ep->maxpacket ? ep->maxpacket : (ep->total_len - + ep->xfer_count); + deptsiz.b.pktcnt = 1; + if (core_if->dma_enable == 0) { + ep->xfer_len += deptsiz.b.xfersize; + } else { + ep->xfer_len = deptsiz.b.xfersize; + } + dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32); + } else { + ep->xfer_len = + (ep->total_len - ep->xfer_count) > + ep->maxpacket ? ep->maxpacket : (ep->total_len - + ep->xfer_count); + + dma_desc = core_if->dev_if->in_desc_addr; + + /** DMA Descriptor Setup */ + dma_desc->status.b.bs = BS_HOST_BUSY; + dma_desc->status.b.l = 1; + dma_desc->status.b.ioc = 1; + dma_desc->status.b.sp = + (ep->xfer_len == ep->maxpacket) ? 0 : 1; + dma_desc->status.b.bytes = ep->xfer_len; + dma_desc->buf = ep->dma_addr; + dma_desc->status.b.bs = BS_HOST_READY; + + /** DIEPDMA0 Register write */ + dwc_write_reg32(&in_regs->diepdma, + core_if->dev_if->dma_in_desc_addr); + } + + DWC_DEBUGPL(DBG_PCDV, + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n", + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt, + deptsiz.d32); + + /* Write the DMA register */ + if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) { + if (core_if->dma_desc_enable == 0) + dwc_write_reg32(&(in_regs->diepdma), + (uint32_t) ep->dma_addr); + } + + /* EP enable, IN data in FIFO */ + depctl.b.cnak = 1; + depctl.b.epena = 1; + dwc_write_reg32(&in_regs->diepctl, depctl.d32); + + /** + * Enable the Non-Periodic Tx FIFO empty interrupt, the + * data will be written into the fifo by the ISR. + */ + if (!core_if->dma_enable) { + if (core_if->en_multiple_tx_fifo == 0) { + /* First clear it from GINTSTS */ + intr_mask.b.nptxfempty = 1; + dwc_modify_reg32(&core_if->core_global_regs-> + gintmsk, intr_mask.d32, + intr_mask.d32); + + } else { + /* Enable the Tx FIFO Empty Interrupt for this EP */ + if (ep->xfer_len > 0) { + uint32_t fifoemptymsk = 0; + fifoemptymsk |= 1 << ep->num; + dwc_modify_reg32(&core_if->dev_if-> + dev_global_regs-> + dtknqr4_fifoemptymsk, + 0, fifoemptymsk); + } + } + } + } else { + dwc_otg_dev_out_ep_regs_t *out_regs = + core_if->dev_if->out_ep_regs[0]; + + depctl.d32 = dwc_read_reg32(&out_regs->doepctl); + deptsiz.d32 = dwc_read_reg32(&out_regs->doeptsiz); + + /* Program the transfer size and packet count + * as follows: xfersize = N * maxpacket + + * short_packet pktcnt = N + (short_packet + * exist ? 1 : 0) + */ + deptsiz.b.xfersize = ep->maxpacket; + deptsiz.b.pktcnt = 1; + + if (core_if->dma_desc_enable == 0) { + dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32); + } else { + dma_desc = core_if->dev_if->out_desc_addr; + + /** DMA Descriptor Setup */ + dma_desc->status.b.bs = BS_HOST_BUSY; + dma_desc->status.b.l = 1; + dma_desc->status.b.ioc = 1; + dma_desc->status.b.bytes = ep->maxpacket; + dma_desc->buf = ep->dma_addr; + dma_desc->status.b.bs = BS_HOST_READY; + + /** DOEPDMA0 Register write */ + dwc_write_reg32(&out_regs->doepdma, + core_if->dev_if->dma_out_desc_addr); + } + + DWC_DEBUGPL(DBG_PCDV, + "IN len=%d xfersize=%d pktcnt=%d [%08x]\n", + ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt, + deptsiz.d32); + + /* Write the DMA register */ + if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) { + if (core_if->dma_desc_enable == 0) + dwc_write_reg32(&(out_regs->doepdma), + (uint32_t) ep->dma_addr); + } + + /* EP enable, IN data in FIFO */ + depctl.b.cnak = 1; + depctl.b.epena = 1; + dwc_write_reg32(&out_regs->doepctl, depctl.d32); + + } +} + +#ifdef DEBUG +void dump_msg(const u8 * buf, unsigned int length) +{ + unsigned int start, num, i; + char line[52], *p; + + if (length >= 512) + return; + start = 0; + while (length > 0) { + num = length < 16u ? length : 16u; + p = line; + for (i = 0; i < num; ++i) { + if (i == 8) + *p++ = ' '; + DWC_SPRINTF(p, " %02x", buf[i]); + p += 3; + } + *p = 0; + DWC_PRINTF("%6x: %s\n", start, line); + buf += num; + start += num; + length -= num; + } +} +#else +static inline void dump_msg(const u8 * buf, unsigned int length) +{ +} +#endif + +/** + * This function writes a packet into the Tx FIFO associated with the + * EP. For non-periodic EPs the non-periodic Tx FIFO is written. For + * periodic EPs the periodic Tx FIFO associated with the EP is written + * with all packets for the next micro-frame. + * + * @param core_if Programming view of DWC_otg controller. + * @param ep The EP to write packet for. + * @param dma Indicates if DMA is being used. + */ +void dwc_otg_ep_write_packet(dwc_otg_core_if_t * core_if, dwc_ep_t * ep, + int dma) +{ + /** + * The buffer is padded to DWORD on a per packet basis in + * slave/dma mode if the MPS is not DWORD aligned. The last + * packet, if short, is also padded to a multiple of DWORD. + * + * ep->xfer_buff always starts DWORD aligned in memory and is a + * multiple of DWORD in length + * + * ep->xfer_len can be any number of bytes + * + * ep->xfer_count is a multiple of ep->maxpacket until the last + * packet + * + * FIFO access is DWORD */ + + uint32_t i; + uint32_t byte_count; + uint32_t dword_count; + uint32_t *fifo; + uint32_t *data_buff = (uint32_t *) ep->xfer_buff; + + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p)\n", __func__, core_if, + ep); + if (ep->xfer_count >= ep->xfer_len) { + DWC_WARN("%s() No data for EP%d!!!\n", __func__, ep->num); + return; + } + + /* Find the byte length of the packet either short packet or MPS */ + if ((ep->xfer_len - ep->xfer_count) < ep->maxpacket) { + byte_count = ep->xfer_len - ep->xfer_count; + } else { + byte_count = ep->maxpacket; + } + + /* Find the DWORD length, padded by extra bytes as neccessary if MPS + * is not a multiple of DWORD */ + dword_count = (byte_count + 3) / 4; + +#ifdef VERBOSE + dump_msg(ep->xfer_buff, byte_count); +#endif + + /**@todo NGS Where are the Periodic Tx FIFO addresses + * intialized? What should this be? */ + + fifo = core_if->data_fifo[ep->num]; + + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "fifo=%p buff=%p *p=%08x bc=%d\n", + fifo, data_buff, *data_buff, byte_count); + + if (!dma) { + for (i = 0; i < dword_count; i++, data_buff++) { + dwc_write_reg32(fifo, *data_buff); + } + } + + ep->xfer_count += byte_count; + ep->xfer_buff += byte_count; + ep->dma_addr += byte_count; +} + +/** + * Set the EP STALL. + * + * @param core_if Programming view of DWC_otg controller. + * @param ep The EP to set the stall on. + */ +void dwc_otg_ep_set_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep) +{ + depctl_data_t depctl; + volatile uint32_t *depctl_addr; + + DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num, + (ep->is_in ? "IN" : "OUT")); + + if (ep->is_in == 1) { + depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl); + depctl.d32 = dwc_read_reg32(depctl_addr); + + /* set the disable and stall bits */ + if (depctl.b.epena) { + depctl.b.epdis = 1; + } + depctl.b.stall = 1; + dwc_write_reg32(depctl_addr, depctl.d32); + } else { + depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl); + depctl.d32 = dwc_read_reg32(depctl_addr); + + /* set the stall bit */ + depctl.b.stall = 1; + dwc_write_reg32(depctl_addr, depctl.d32); + } + + DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", dwc_read_reg32(depctl_addr)); + + return; +} + +/** + * Clear the EP STALL. + * + * @param core_if Programming view of DWC_otg controller. + * @param ep The EP to clear stall from. + */ +void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * core_if, dwc_ep_t * ep) +{ + depctl_data_t depctl; + volatile uint32_t *depctl_addr; + + DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num, + (ep->is_in ? "IN" : "OUT")); + + if (ep->is_in == 1) { + depctl_addr = &(core_if->dev_if->in_ep_regs[ep->num]->diepctl); + } else { + depctl_addr = &(core_if->dev_if->out_ep_regs[ep->num]->doepctl); + } + + depctl.d32 = dwc_read_reg32(depctl_addr); + + /* clear the stall bits */ + depctl.b.stall = 0; + + /* + * USB Spec 9.4.5: For endpoints using data toggle, regardless + * of whether an endpoint has the Halt feature set, a + * ClearFeature(ENDPOINT_HALT) request always results in the + * data toggle being reinitialized to DATA0. + */ + if (ep->type == DWC_OTG_EP_TYPE_INTR || + ep->type == DWC_OTG_EP_TYPE_BULK) { + depctl.b.setd0pid = 1; /* DATA0 */ + } + + dwc_write_reg32(depctl_addr, depctl.d32); + DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", dwc_read_reg32(depctl_addr)); + return; +} + +/** + * This function reads a packet from the Rx FIFO into the destination + * buffer. To read SETUP data use dwc_otg_read_setup_packet. + * + * @param core_if Programming view of DWC_otg controller. + * @param dest Destination buffer for the packet. + * @param bytes Number of bytes to copy to the destination. + */ +void dwc_otg_read_packet(dwc_otg_core_if_t * core_if, + uint8_t * dest, uint16_t bytes) +{ + int i; + int word_count = (bytes + 3) / 4; + + volatile uint32_t *fifo = core_if->data_fifo[0]; + uint32_t *data_buff = (uint32_t *) dest; + + /** + * @todo Account for the case where _dest is not dword aligned. This + * requires reading data from the FIFO into a uint32_t temp buffer, + * then moving it into the data buffer. + */ + + DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p,%d)\n", __func__, + core_if, dest, bytes); + + for (i = 0; i < word_count; i++, data_buff++) { + *data_buff = dwc_read_reg32(fifo); + } + + return; +} + +/** + * This functions reads the device registers and prints them + * + * @param core_if Programming view of DWC_otg controller. + */ +void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * core_if) +{ + int i; + volatile uint32_t *addr; + + DWC_PRINTF("Device Global Registers\n"); + addr = &core_if->dev_if->dev_global_regs->dcfg; + DWC_PRINTF("DCFG @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->dev_if->dev_global_regs->dctl; + DWC_PRINTF("DCTL @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->dev_if->dev_global_regs->dsts; + DWC_PRINTF("DSTS @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->dev_if->dev_global_regs->diepmsk; + DWC_PRINTF("DIEPMSK @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->dev_if->dev_global_regs->doepmsk; + DWC_PRINTF("DOEPMSK @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->dev_if->dev_global_regs->daint; + DWC_PRINTF("DAINT @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->dev_if->dev_global_regs->daintmsk; + DWC_PRINTF("DAINTMSK @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->dev_if->dev_global_regs->dtknqr1; + DWC_PRINTF("DTKNQR1 @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + if (core_if->hwcfg2.b.dev_token_q_depth > 6) { + addr = &core_if->dev_if->dev_global_regs->dtknqr2; + DWC_PRINTF("DTKNQR2 @0x%08X : 0x%08X\n", + (uint32_t) addr, dwc_read_reg32(addr)); + } + + addr = &core_if->dev_if->dev_global_regs->dvbusdis; + DWC_PRINTF("DVBUSID @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + + addr = &core_if->dev_if->dev_global_regs->dvbuspulse; + DWC_PRINTF("DVBUSPULSE @0x%08X : 0x%08X\n", + (uint32_t) addr, dwc_read_reg32(addr)); + + addr = &core_if->dev_if->dev_global_regs->dtknqr3_dthrctl; + DWC_PRINTF("DTKNQR3_DTHRCTL @0x%08X : 0x%08X\n", + (uint32_t) addr, dwc_read_reg32(addr)); + + if (core_if->hwcfg2.b.dev_token_q_depth > 22) { + addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk; + DWC_PRINTF("DTKNQR4 @0x%08X : 0x%08X\n", + (uint32_t) addr, dwc_read_reg32(addr)); + } + + addr = &core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk; + DWC_PRINTF("FIFOEMPMSK @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + + addr = &core_if->dev_if->dev_global_regs->deachint; + DWC_PRINTF("DEACHINT @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->dev_if->dev_global_regs->deachintmsk; + DWC_PRINTF("DEACHINTMSK @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) { + addr = &core_if->dev_if->dev_global_regs->diepeachintmsk[i]; + DWC_PRINTF("DIEPEACHINTMSK[%d] @0x%08X : 0x%08X\n", i, + (uint32_t) addr, dwc_read_reg32(addr)); + } + + for (i = 0; i <= core_if->dev_if->num_out_eps; i++) { + addr = &core_if->dev_if->dev_global_regs->doepeachintmsk[i]; + DWC_PRINTF("DOEPEACHINTMSK[%d] @0x%08X : 0x%08X\n", i, + (uint32_t) addr, dwc_read_reg32(addr)); + } + + for (i = 0; i <= core_if->dev_if->num_in_eps; i++) { + DWC_PRINTF("Device IN EP %d Registers\n", i); + addr = &core_if->dev_if->in_ep_regs[i]->diepctl; + DWC_PRINTF("DIEPCTL @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->dev_if->in_ep_regs[i]->diepint; + DWC_PRINTF("DIEPINT @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->dev_if->in_ep_regs[i]->dieptsiz; + DWC_PRINTF("DIETSIZ @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->dev_if->in_ep_regs[i]->diepdma; + DWC_PRINTF("DIEPDMA @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->dev_if->in_ep_regs[i]->dtxfsts; + DWC_PRINTF("DTXFSTS @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->dev_if->in_ep_regs[i]->diepdmab; + DWC_PRINTF("DIEPDMAB @0x%08X : 0x%08X\n", (uint32_t) addr, + 0 /*dwc_read_reg32(addr) */ ); + } + + for (i = 0; i <= core_if->dev_if->num_out_eps; i++) { + DWC_PRINTF("Device OUT EP %d Registers\n", i); + addr = &core_if->dev_if->out_ep_regs[i]->doepctl; + DWC_PRINTF("DOEPCTL @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->dev_if->out_ep_regs[i]->doepfn; + DWC_PRINTF("DOEPFN @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->dev_if->out_ep_regs[i]->doepint; + DWC_PRINTF("DOEPINT @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->dev_if->out_ep_regs[i]->doeptsiz; + DWC_PRINTF("DOETSIZ @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->dev_if->out_ep_regs[i]->doepdma; + DWC_PRINTF("DOEPDMA @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + if (core_if->dma_enable) { /* Don't access this register in SLAVE mode */ + addr = &core_if->dev_if->out_ep_regs[i]->doepdmab; + DWC_PRINTF("DOEPDMAB @0x%08X : 0x%08X\n", + (uint32_t) addr, dwc_read_reg32(addr)); + } + + } +} + +/** + * This functions reads the SPRAM and prints its content + * + * @param core_if Programming view of DWC_otg controller. + */ +void dwc_otg_dump_spram(dwc_otg_core_if_t * core_if) +{ + volatile uint8_t *addr, *start_addr, *end_addr; + + DWC_PRINTF("SPRAM Data:\n"); + start_addr = (void *)core_if->core_global_regs; + DWC_PRINTF("Base Address: 0x%8X\n", (uint32_t) start_addr); + start_addr += 0x00028000; + end_addr = (void *)core_if->core_global_regs; + end_addr += 0x000280e0; + + for (addr = start_addr; addr < end_addr; addr += 16) { + DWC_PRINTF + ("0x%8X:\t%2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X %2X\n", + (uint32_t) addr, addr[0], addr[1], addr[2], addr[3], + addr[4], addr[5], addr[6], addr[7], addr[8], addr[9], + addr[10], addr[11], addr[12], addr[13], addr[14], addr[15] + ); + } + + return; +} + +/** + * This function reads the host registers and prints them + * + * @param core_if Programming view of DWC_otg controller. + */ +void dwc_otg_dump_host_registers(dwc_otg_core_if_t * core_if) +{ + int i; + volatile uint32_t *addr; + + DWC_PRINTF("Host Global Registers\n"); + addr = &core_if->host_if->host_global_regs->hcfg; + DWC_PRINTF("HCFG @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->host_if->host_global_regs->hfir; + DWC_PRINTF("HFIR @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->host_if->host_global_regs->hfnum; + DWC_PRINTF("HFNUM @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->host_if->host_global_regs->hptxsts; + DWC_PRINTF("HPTXSTS @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->host_if->host_global_regs->haint; + DWC_PRINTF("HAINT @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->host_if->host_global_regs->haintmsk; + DWC_PRINTF("HAINTMSK @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + if (core_if->dma_desc_enable) { + addr = &core_if->host_if->host_global_regs->hflbaddr; + DWC_PRINTF("HFLBADDR @0x%08X : 0x%08X\n",(uint32_t) addr, + dwc_read_reg32(addr)); + } + + addr = core_if->host_if->hprt0; + DWC_PRINTF("HPRT0 @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + + for (i = 0; i < core_if->core_params->host_channels; i++) { + DWC_PRINTF("Host Channel %d Specific Registers\n", i); + addr = &core_if->host_if->hc_regs[i]->hcchar; + DWC_PRINTF("HCCHAR @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->host_if->hc_regs[i]->hcsplt; + DWC_PRINTF("HCSPLT @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->host_if->hc_regs[i]->hcint; + DWC_PRINTF("HCINT @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->host_if->hc_regs[i]->hcintmsk; + DWC_PRINTF("HCINTMSK @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->host_if->hc_regs[i]->hctsiz; + DWC_PRINTF("HCTSIZ @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->host_if->hc_regs[i]->hcdma; + DWC_PRINTF("HCDMA @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + if (core_if->dma_desc_enable) { + addr=&core_if->host_if->hc_regs[i]->hcdmab; + DWC_PRINTF("HCDMAB @0x%08X : 0x%08X\n",(uint32_t) addr, dwc_read_reg32(addr)); + } + + } + return; +} + +/** + * This function reads the core global registers and prints them + * + * @param core_if Programming view of DWC_otg controller. + */ +void dwc_otg_dump_global_registers(dwc_otg_core_if_t * core_if) +{ + int i; + volatile uint32_t *addr; + + DWC_PRINTF("Core Global Registers\n"); + addr = &core_if->core_global_regs->gotgctl; + DWC_PRINTF("GOTGCTL @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->gotgint; + DWC_PRINTF("GOTGINT @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->gahbcfg; + DWC_PRINTF("GAHBCFG @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->gusbcfg; + DWC_PRINTF("GUSBCFG @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->grstctl; + DWC_PRINTF("GRSTCTL @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->gintsts; + DWC_PRINTF("GINTSTS @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->gintmsk; + DWC_PRINTF("GINTMSK @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->grxstsr; + DWC_PRINTF("GRXSTSR @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->grxfsiz; + DWC_PRINTF("GRXFSIZ @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->gnptxfsiz; + DWC_PRINTF("GNPTXFSIZ @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->gnptxsts; + DWC_PRINTF("GNPTXSTS @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->gi2cctl; + DWC_PRINTF("GI2CCTL @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->gpvndctl; + DWC_PRINTF("GPVNDCTL @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->ggpio; + DWC_PRINTF("GGPIO @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->guid; + DWC_PRINTF("GUID @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->gsnpsid; + DWC_PRINTF("GSNPSID @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->ghwcfg1; + DWC_PRINTF("GHWCFG1 @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->ghwcfg2; + DWC_PRINTF("GHWCFG2 @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->ghwcfg3; + DWC_PRINTF("GHWCFG3 @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->ghwcfg4; + DWC_PRINTF("GHWCFG4 @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->glpmcfg; + DWC_PRINTF("GLPMCFG @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + addr = &core_if->core_global_regs->hptxfsiz; + DWC_PRINTF("HPTXFSIZ @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); + + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) { + addr = &core_if->core_global_regs->dptxfsiz_dieptxf[i]; + DWC_PRINTF("DPTXFSIZ[%d] @0x%08X : 0x%08X\n", i, + (uint32_t) addr, dwc_read_reg32(addr)); + } + addr = core_if->pcgcctl; + DWC_PRINTF("PCGCCTL @0x%08X : 0x%08X\n", (uint32_t) addr, + dwc_read_reg32(addr)); +} + +/** + * Flush a Tx FIFO. + * + * @param core_if Programming view of DWC_otg controller. + * @param num Tx FIFO to flush. + */ +void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * core_if, const int num) +{ + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; + volatile grstctl_t greset = {.d32 = 0 }; + int count = 0; + + DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "Flush Tx FIFO %d\n", num); + + greset.b.txfflsh = 1; + greset.b.txfnum = num; + dwc_write_reg32(&global_regs->grstctl, greset.d32); + + do { + greset.d32 = dwc_read_reg32(&global_regs->grstctl); + if (++count > 10000) { + DWC_WARN("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n", + __func__, greset.d32, + dwc_read_reg32(&global_regs->gnptxsts)); + break; + } + dwc_udelay(1); + } while (greset.b.txfflsh == 1); + + /* Wait for 3 PHY Clocks */ + dwc_udelay(1); +} + +/** + * Flush Rx FIFO. + * + * @param core_if Programming view of DWC_otg controller. + */ +void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * core_if) +{ + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; + volatile grstctl_t greset = {.d32 = 0 }; + int count = 0; + + DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "%s\n", __func__); + /* + * + */ + greset.b.rxfflsh = 1; + dwc_write_reg32(&global_regs->grstctl, greset.d32); + + do { + greset.d32 = dwc_read_reg32(&global_regs->grstctl); + if (++count > 10000) { + DWC_WARN("%s() HANG! GRSTCTL=%0x\n", __func__, + greset.d32); + break; + } + dwc_udelay(1); + } while (greset.b.rxfflsh == 1); + + /* Wait for 3 PHY Clocks */ + dwc_udelay(1); +} + +/** + * Do core a soft reset of the core. Be careful with this because it + * resets all the internal state machines of the core. + */ +void dwc_otg_core_reset(dwc_otg_core_if_t * core_if) +{ + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; + volatile grstctl_t greset = {.d32 = 0 }; + int count = 0; + + DWC_DEBUGPL(DBG_CILV, "%s\n", __func__); + /* Wait for AHB master IDLE state. */ + do { + dwc_udelay(10); + greset.d32 = dwc_read_reg32(&global_regs->grstctl); + if (++count > 100000) { + DWC_WARN("%s() HANG! AHB Idle GRSTCTL=%0x\n", __func__, + greset.d32); + return; + } + } + while (greset.b.ahbidle == 0); + + /* Core Soft Reset */ + count = 0; + greset.b.csftrst = 1; + dwc_write_reg32(&global_regs->grstctl, greset.d32); + do { + greset.d32 = dwc_read_reg32(&global_regs->grstctl); + if (++count > 10000) { + DWC_WARN("%s() HANG! Soft Reset GRSTCTL=%0x\n", + __func__, greset.d32); + break; + } + dwc_udelay(1); + } + while (greset.b.csftrst == 1); + + /* Wait for 3 PHY Clocks */ + dwc_mdelay(100); +} + +uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if) +{ + return (dwc_otg_mode(_core_if) != DWC_HOST_MODE); +} + +uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if) +{ + return (dwc_otg_mode(_core_if) == DWC_HOST_MODE); +} + +/** + * Register HCD callbacks. The callbacks are used to start and stop + * the HCD for interrupt processing. + * + * @param core_if Programming view of DWC_otg controller. + * @param cb the HCD callback structure. + * @param p pointer to be passed to callback function (usb_hcd*). + */ +void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * core_if, + dwc_otg_cil_callbacks_t * cb, void *p) +{ + core_if->hcd_cb = cb; + cb->p = p; +} + +/** + * Register PCD callbacks. The callbacks are used to start and stop + * the PCD for interrupt processing. + * + * @param core_if Programming view of DWC_otg controller. + * @param cb the PCD callback structure. + * @param p pointer to be passed to callback function (pcd*). + */ +void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * core_if, + dwc_otg_cil_callbacks_t * cb, void *p) +{ + core_if->pcd_cb = cb; + cb->p = p; +} + +#ifdef DWC_EN_ISOC + +/** + * This function writes isoc data per 1 (micro)frame into tx fifo + * + * @param core_if Programming view of DWC_otg controller. + * @param ep The EP to start the transfer on. + * + */ +void write_isoc_frame_data(dwc_otg_core_if_t * core_if, dwc_ep_t * ep) +{ + dwc_otg_dev_in_ep_regs_t *ep_regs; + dtxfsts_data_t txstatus = {.d32 = 0 }; + uint32_t len = 0; + uint32_t dwords; + + ep->xfer_len = ep->data_per_frame; + ep->xfer_count = 0; + + ep_regs = core_if->dev_if->in_ep_regs[ep->num]; + + len = ep->xfer_len - ep->xfer_count; + + if (len > ep->maxpacket) { + len = ep->maxpacket; + } + + dwords = (len + 3) / 4; + + /* While there is space in the queue and space in the FIFO and + * More data to tranfer, Write packets to the Tx FIFO */ + txstatus.d32 = + dwc_read_reg32(&core_if->dev_if->in_ep_regs[ep->num]->dtxfsts); + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", ep->num, txstatus.d32); + + while (txstatus.b.txfspcavail > dwords && + ep->xfer_count < ep->xfer_len && ep->xfer_len != 0) { + /* Write the FIFO */ + dwc_otg_ep_write_packet(core_if, ep, 0); + + len = ep->xfer_len - ep->xfer_count; + if (len > ep->maxpacket) { + len = ep->maxpacket; + } + + dwords = (len + 3) / 4; + txstatus.d32 = + dwc_read_reg32(&core_if->dev_if->in_ep_regs[ep->num]-> + dtxfsts); + DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", ep->num, + txstatus.d32); + } +} + +/** + * This function initializes a descriptor chain for Isochronous transfer + * + * @param core_if Programming view of DWC_otg controller. + * @param ep The EP to start the transfer on. + * + */ +void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if, + dwc_ep_t * ep) +{ + deptsiz_data_t deptsiz = {.d32 = 0 }; + depctl_data_t depctl = {.d32 = 0 }; + dsts_data_t dsts = {.d32 = 0 }; + volatile uint32_t *addr; + + if (ep->is_in) { + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl; + } else { + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl; + } + + ep->xfer_len = ep->data_per_frame; + ep->xfer_count = 0; + ep->xfer_buff = ep->cur_pkt_addr; + ep->dma_addr = ep->cur_pkt_dma_addr; + + if (ep->is_in) { + /* Program the transfer size and packet count + * as follows: xfersize = N * maxpacket + + * short_packet pktcnt = N + (short_packet + * exist ? 1 : 0) + */ + deptsiz.b.xfersize = ep->xfer_len; + deptsiz.b.pktcnt = + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket; + deptsiz.b.mc = deptsiz.b.pktcnt; + dwc_write_reg32(&core_if->dev_if->in_ep_regs[ep->num]->dieptsiz, + deptsiz.d32); + + /* Write the DMA register */ + if (core_if->dma_enable) { + dwc_write_reg32(& + (core_if->dev_if->in_ep_regs[ep->num]-> + diepdma), (uint32_t) ep->dma_addr); + } + } else { + deptsiz.b.pktcnt = + (ep->xfer_len + (ep->maxpacket - 1)) / ep->maxpacket; + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket; + + dwc_write_reg32(&core_if->dev_if->out_ep_regs[ep->num]-> + doeptsiz, deptsiz.d32); + + if (core_if->dma_enable) { + dwc_write_reg32(& + (core_if->dev_if->out_ep_regs[ep->num]-> + doepdma), (uint32_t) ep->dma_addr); + } + } + + /** Enable endpoint, clear nak */ + + depctl.d32 = 0; + if (ep->bInterval == 1) { + dsts.d32 = + dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts); + ep->next_frame = dsts.b.soffn + ep->bInterval; + + if (ep->next_frame & 0x1) { + depctl.b.setd1pid = 1; + } else { + depctl.b.setd0pid = 1; + } + } else { + ep->next_frame += ep->bInterval; + + if (ep->next_frame & 0x1) { + depctl.b.setd1pid = 1; + } else { + depctl.b.setd0pid = 1; + } + } + depctl.b.epena = 1; + depctl.b.cnak = 1; + + dwc_modify_reg32(addr, 0, depctl.d32); + depctl.d32 = dwc_read_reg32(addr); + + if (ep->is_in && core_if->dma_enable == 0) { + write_isoc_frame_data(core_if, ep); + } + +} +#endif /* DWC_EN_ISOC */ + +static void dwc_otg_set_uninitialized(int32_t * p, int size) +{ + int i; + for (i = 0; i < size; i++) { + p[i] = -1; + } +} + +static int dwc_otg_param_initialized(int32_t val) +{ + return val != -1; +} + +static int dwc_otg_setup_params(dwc_otg_core_if_t * core_if) +{ + int i; + core_if->core_params = DWC_ALLOC(sizeof(*core_if->core_params)); + if (!core_if->core_params) { + return -DWC_E_NO_MEMORY; + } + dwc_otg_set_uninitialized((int32_t *) core_if->core_params, + sizeof(*core_if->core_params) / + sizeof(int32_t)); + DWC_PRINTF("Setting default values for core params\n"); + dwc_otg_set_param_otg_cap(core_if, dwc_param_otg_cap_default); + dwc_otg_set_param_dma_enable(core_if, dwc_param_dma_enable_default); + dwc_otg_set_param_dma_desc_enable(core_if, + dwc_param_dma_desc_enable_default); + dwc_otg_set_param_opt(core_if, dwc_param_opt_default); + dwc_otg_set_param_dma_burst_size(core_if, + dwc_param_dma_burst_size_default); + dwc_otg_set_param_host_support_fs_ls_low_power(core_if, + dwc_param_host_support_fs_ls_low_power_default); + dwc_otg_set_param_enable_dynamic_fifo(core_if, + dwc_param_enable_dynamic_fifo_default); + dwc_otg_set_param_data_fifo_size(core_if, + dwc_param_data_fifo_size_default); + dwc_otg_set_param_dev_rx_fifo_size(core_if, + dwc_param_dev_rx_fifo_size_default); + dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if, + dwc_param_dev_nperio_tx_fifo_size_default); + dwc_otg_set_param_host_rx_fifo_size(core_if, + dwc_param_host_rx_fifo_size_default); + dwc_otg_set_param_host_nperio_tx_fifo_size(core_if, + dwc_param_host_nperio_tx_fifo_size_default); + dwc_otg_set_param_host_perio_tx_fifo_size(core_if, + dwc_param_host_perio_tx_fifo_size_default); + dwc_otg_set_param_max_transfer_size(core_if, + dwc_param_max_transfer_size_default); + dwc_otg_set_param_max_packet_count(core_if, + dwc_param_max_packet_count_default); + dwc_otg_set_param_host_channels(core_if, + dwc_param_host_channels_default); + dwc_otg_set_param_dev_endpoints(core_if, + dwc_param_dev_endpoints_default); + dwc_otg_set_param_phy_type(core_if, dwc_param_phy_type_default); + dwc_otg_set_param_speed(core_if, dwc_param_speed_default); + dwc_otg_set_param_host_ls_low_power_phy_clk(core_if, + dwc_param_host_ls_low_power_phy_clk_default); + dwc_otg_set_param_phy_ulpi_ddr(core_if, dwc_param_phy_ulpi_ddr_default); + dwc_otg_set_param_phy_ulpi_ext_vbus(core_if, + dwc_param_phy_ulpi_ext_vbus_default); + dwc_otg_set_param_phy_utmi_width(core_if, + dwc_param_phy_utmi_width_default); + dwc_otg_set_param_ts_dline(core_if, dwc_param_ts_dline_default); + dwc_otg_set_param_i2c_enable(core_if, dwc_param_i2c_enable_default); + dwc_otg_set_param_ulpi_fs_ls(core_if, dwc_param_ulpi_fs_ls_default); + dwc_otg_set_param_en_multiple_tx_fifo(core_if, + dwc_param_en_multiple_tx_fifo_default); + for (i = 0; i < 15; i++) { + dwc_otg_set_param_dev_perio_tx_fifo_size(core_if, + dwc_param_dev_perio_tx_fifo_size_default, + i); + } + + for (i = 0; i < 15; i++) { + dwc_otg_set_param_dev_tx_fifo_size(core_if, + dwc_param_dev_tx_fifo_size_default, + i); + } + dwc_otg_set_param_thr_ctl(core_if, dwc_param_thr_ctl_default); + dwc_otg_set_param_mpi_enable(core_if, dwc_param_mpi_enable_default); + dwc_otg_set_param_pti_enable(core_if, dwc_param_pti_enable_default); + dwc_otg_set_param_lpm_enable(core_if, dwc_param_lpm_enable_default); + dwc_otg_set_param_ic_usb_cap(core_if, dwc_param_ic_usb_cap_default); + dwc_otg_set_param_tx_thr_length(core_if, + dwc_param_tx_thr_length_default); + dwc_otg_set_param_rx_thr_length(core_if, + dwc_param_rx_thr_length_default); + dwc_otg_set_param_ahb_thr_ratio(core_if, dwc_param_ahb_thr_ratio_default); + DWC_PRINTF("Finished setting default values for core params\n"); + return 0; +} + +uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if) +{ + return core_if->dma_enable; +} + +/* Checks if the parameter is outside of its valid range of values */ +#define DWC_OTG_PARAM_TEST(_param_, _low_, _high_) \ + (((_param_) < (_low_)) || \ + ((_param_) > (_high_))) + +/* Parameter access functions */ +int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val) +{ + int valid; + int retval = 0; + if (DWC_OTG_PARAM_TEST(val, 0, 2)) { + DWC_WARN("Wrong value for otg_cap parameter\n"); + DWC_WARN("otg_cap parameter must be 0,1 or 2\n"); + retval = -DWC_E_INVALID; + goto out; + } + + valid = 1; + switch (val) { + case DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE: + if (core_if->hwcfg2.b.op_mode != + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) + valid = 0; + break; + case DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE: + if ((core_if->hwcfg2.b.op_mode != + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) + && (core_if->hwcfg2.b.op_mode != + DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG) + && (core_if->hwcfg2.b.op_mode != + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) + && (core_if->hwcfg2.b.op_mode != + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) { + valid = 0; + } + break; + case DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE: + /* always valid */ + break; + } + if (!valid) { + if (dwc_otg_param_initialized(core_if->core_params->otg_cap)) { + DWC_ERROR + ("%d invalid for otg_cap paremter. Check HW configuration.\n", + val); + } + val = + (((core_if->hwcfg2.b.op_mode == + DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) + || (core_if->hwcfg2.b.op_mode == + DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG) + || (core_if->hwcfg2.b.op_mode == + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) + || (core_if->hwcfg2.b.op_mode == + DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) ? + DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE : + DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE); + retval = -DWC_E_INVALID; + } + + core_if->core_params->otg_cap = val; + out: + return retval; +} + +int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->otg_cap; +} + +int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val) +{ + if (DWC_OTG_PARAM_TEST(val, 0, 1)) { + DWC_WARN("Wrong value for opt parameter\n"); + return -DWC_E_INVALID; + } + core_if->core_params->opt = val; + return 0; +} + +int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->opt; +} + +int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if, int32_t val) +{ + int retval = 0; + if (DWC_OTG_PARAM_TEST(val, 0, 1)) { + DWC_WARN("Wrong value for dma enable\n"); + return -DWC_E_INVALID; + } + + if ((val == 1) && (core_if->hwcfg2.b.architecture == 0)) { + if (dwc_otg_param_initialized(core_if->core_params->dma_enable)) { + DWC_ERROR + ("%d invalid for dma_enable paremter. Check HW configuration.\n", + val); + } + val = 0; + retval = -DWC_E_INVALID; + } + + core_if->core_params->dma_enable = val; + if (val == 0) { + dwc_otg_set_param_dma_desc_enable(core_if, 0); + } + return retval; +} + +int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->dma_enable; +} + +int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if, int32_t val) +{ + int retval = 0; + if (DWC_OTG_PARAM_TEST(val, 0, 1)) { + DWC_WARN("Wrong value for dma_enable\n"); + DWC_WARN("dma_desc_enable must be 0 or 1\n"); + return -DWC_E_INVALID; + } + + if ((val == 1) + && ((dwc_otg_get_param_dma_enable(core_if) == 0) + || (core_if->hwcfg4.b.desc_dma == 0))) { + if (dwc_otg_param_initialized + (core_if->core_params->dma_desc_enable)) { + DWC_ERROR + ("%d invalid for dma_desc_enable paremter. Check HW configuration.\n", + val); + } + val = 0; + retval = -DWC_E_INVALID; + } + core_if->core_params->dma_desc_enable = val; + return retval; +} + +int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->dma_desc_enable; +} + +int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t * core_if, + int32_t val) +{ + if (DWC_OTG_PARAM_TEST(val, 0, 1)) { + DWC_WARN("Wrong value for host_support_fs_low_power\n"); + DWC_WARN("host_support_fs_low_power must be 0 or 1\n"); + return -DWC_E_INVALID; + } + core_if->core_params->host_support_fs_ls_low_power = val; + return 0; +} + +int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t * + core_if) +{ + return core_if->core_params->host_support_fs_ls_low_power; +} + +int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if, + int32_t val) +{ + int retval = 0; + if (DWC_OTG_PARAM_TEST(val, 0, 1)) { + DWC_WARN("Wrong value for enable_dynamic_fifo\n"); + DWC_WARN("enable_dynamic_fifo must be 0 or 1\n"); + return -DWC_E_INVALID; + } + + if ((val == 1) && (core_if->hwcfg2.b.dynamic_fifo == 0)) { + if (dwc_otg_param_initialized + (core_if->core_params->enable_dynamic_fifo)) { + DWC_ERROR + ("%d invalid for enable_dynamic_fifo paremter. Check HW configuration.\n", + val); + } + val = 0; + retval = -DWC_E_INVALID; + } + core_if->core_params->enable_dynamic_fifo = val; + return retval; +} + +int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->enable_dynamic_fifo; +} + +int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if, int32_t val) +{ + int retval = 0; + if (DWC_OTG_PARAM_TEST(val, 32, 32768)) { + DWC_WARN("Wrong value for data_fifo_size\n"); + DWC_WARN("data_fifo_size must be 32-32768\n"); + return -DWC_E_INVALID; + } + + if (val > core_if->hwcfg3.b.dfifo_depth) { + if (dwc_otg_param_initialized + (core_if->core_params->data_fifo_size)) { + DWC_ERROR + ("%d invalid for data_fifo_size parameter. Check HW configuration.\n", + val); + } + val = core_if->hwcfg3.b.dfifo_depth; + retval = -DWC_E_INVALID; + } + + core_if->core_params->data_fifo_size = val; + return retval; +} + +int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->data_fifo_size; +} + +int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val) +{ + int retval = 0; + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) { + DWC_WARN("Wrong value for dev_rx_fifo_size\n"); + DWC_WARN("dev_rx_fifo_size must be 16-32768\n"); + return -DWC_E_INVALID; + } + + if (val > dwc_read_reg32(&core_if->core_global_regs->grxfsiz)) { + if(dwc_otg_param_initialized(core_if->core_params->dev_rx_fifo_size)) { + DWC_WARN("%d invalid for dev_rx_fifo_size parameter\n", val); + } + val = dwc_read_reg32(&core_if->core_global_regs->grxfsiz); + retval = -DWC_E_INVALID; + } + + core_if->core_params->dev_rx_fifo_size = val; + return retval; +} + +int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->dev_rx_fifo_size; +} + +int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if, + int32_t val) +{ + int retval = 0; + + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) { + DWC_WARN("Wrong value for dev_nperio_tx_fifo\n"); + DWC_WARN("dev_nperio_tx_fifo must be 16-32768\n"); + return -DWC_E_INVALID; + } + + if (val > (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)) { + if (dwc_otg_param_initialized + (core_if->core_params->dev_nperio_tx_fifo_size)) { + DWC_ERROR + ("%d invalid for dev_nperio_tx_fifo_size. Check HW configuration.\n", + val); + } + val = + (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> + 16); + retval = -DWC_E_INVALID; + } + + core_if->core_params->dev_nperio_tx_fifo_size = val; + return retval; +} + +int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->dev_nperio_tx_fifo_size; +} + +int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if, + int32_t val) +{ + int retval = 0; + + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) { + DWC_WARN("Wrong value for host_rx_fifo_size\n"); + DWC_WARN("host_rx_fifo_size must be 16-32768\n"); + return -DWC_E_INVALID; + } + + if (val > dwc_read_reg32(&core_if->core_global_regs->grxfsiz)) { + if (dwc_otg_param_initialized + (core_if->core_params->host_rx_fifo_size)) { + DWC_ERROR + ("%d invalid for host_rx_fifo_size. Check HW configuration.\n", + val); + } + val = dwc_read_reg32(&core_if->core_global_regs->grxfsiz); + retval = -DWC_E_INVALID; + } + + core_if->core_params->host_rx_fifo_size = val; + return retval; + +} + +int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->host_rx_fifo_size; +} + +int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if, + int32_t val) +{ + int retval = 0; + + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) { + DWC_WARN("Wrong value for host_nperio_tx_fifo_size\n"); + DWC_WARN("host_nperio_tx_fifo_size must be 16-32768\n"); + return -DWC_E_INVALID; + } + + if (val > (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)) { + if (dwc_otg_param_initialized + (core_if->core_params->host_nperio_tx_fifo_size)) { + DWC_ERROR + ("%d invalid for host_nperio_tx_fifo_size. Check HW configuration.\n", + val); + } + val = + (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> + 16); + retval = -DWC_E_INVALID; + } + + core_if->core_params->host_nperio_tx_fifo_size = val; + return retval; +} + +int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->host_nperio_tx_fifo_size; +} + +int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if, + int32_t val) +{ + int retval = 0; + if (DWC_OTG_PARAM_TEST(val, 16, 32768)) { + DWC_WARN("Wrong value for host_perio_tx_fifo_size\n"); + DWC_WARN("host_perio_tx_fifo_size must be 16-32768\n"); + return -DWC_E_INVALID; + } + + if (val > + ((dwc_read_reg32(&core_if->core_global_regs->hptxfsiz) >> 16))) { + if (dwc_otg_param_initialized + (core_if->core_params->host_perio_tx_fifo_size)) { + DWC_ERROR + ("%d invalid for host_perio_tx_fifo_size. Check HW configuration.\n", + val); + } + val = + (dwc_read_reg32(&core_if->core_global_regs->hptxfsiz) >> + 16); + retval = -DWC_E_INVALID; + } + + core_if->core_params->host_perio_tx_fifo_size = val; + return retval; +} + +int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->host_perio_tx_fifo_size; +} + +int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if, + int32_t val) +{ + int retval = 0; + + if (DWC_OTG_PARAM_TEST(val, 2047, 524288)) { + DWC_WARN("Wrong value for max_transfer_size\n"); + DWC_WARN("max_transfer_size must be 2047-524288\n"); + return -DWC_E_INVALID; + } + + if (val >= (1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11))) { + if (dwc_otg_param_initialized + (core_if->core_params->max_transfer_size)) { + DWC_ERROR + ("%d invalid for max_transfer_size. Check HW configuration.\n", + val); + } + val = + ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 11)) - + 1); + retval = -DWC_E_INVALID; + } + + core_if->core_params->max_transfer_size = val; + return retval; +} + +int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->max_transfer_size; +} + +int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if, int32_t val) +{ + int retval = 0; + + if (DWC_OTG_PARAM_TEST(val, 15, 511)) { + DWC_WARN("Wrong value for max_packet_count\n"); + DWC_WARN("max_packet_count must be 15-511\n"); + return -DWC_E_INVALID; + } + + if (val > (1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4))) { + if (dwc_otg_param_initialized + (core_if->core_params->max_packet_count)) { + DWC_ERROR + ("%d invalid for max_packet_count. Check HW configuration.\n", + val); + } + val = + ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1); + retval = -DWC_E_INVALID; + } + + core_if->core_params->max_packet_count = val; + return retval; +} + +int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->max_packet_count; +} + +int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if, int32_t val) +{ + int retval = 0; + + if (DWC_OTG_PARAM_TEST(val, 1, 16)) { + DWC_WARN("Wrong value for host_channels\n"); + DWC_WARN("host_channels must be 1-16\n"); + return -DWC_E_INVALID; + } + + if (val > (core_if->hwcfg2.b.num_host_chan + 1)) { + if (dwc_otg_param_initialized + (core_if->core_params->host_channels)) { + DWC_ERROR + ("%d invalid for host_channels. Check HW configurations.\n", + val); + } + val = (core_if->hwcfg2.b.num_host_chan + 1); + retval = -DWC_E_INVALID; + } + + core_if->core_params->host_channels = val; + return retval; +} + +int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->host_channels; +} + +int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if, int32_t val) +{ + int retval = 0; + + if (DWC_OTG_PARAM_TEST(val, 1, 15)) { + DWC_WARN("Wrong value for dev_endpoints\n"); + DWC_WARN("dev_endpoints must be 1-15\n"); + return -DWC_E_INVALID; + } + + if (val > (core_if->hwcfg2.b.num_dev_ep)) { + if (dwc_otg_param_initialized + (core_if->core_params->dev_endpoints)) { + DWC_ERROR + ("%d invalid for dev_endpoints. Check HW configurations.\n", + val); + } + val = core_if->hwcfg2.b.num_dev_ep; + retval = -DWC_E_INVALID; + } + + core_if->core_params->dev_endpoints = val; + return retval; +} + +int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->dev_endpoints; +} + +int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val) +{ + int retval = 0; + int valid = 0; + + if (DWC_OTG_PARAM_TEST(val, 0, 2)) { + DWC_WARN("Wrong value for phy_type\n"); + DWC_WARN("phy_type must be 0,1 or 2\n"); + return -DWC_E_INVALID; + } +#ifndef NO_FS_PHY_HW_CHECKS + if ((val == DWC_PHY_TYPE_PARAM_UTMI) && + ((core_if->hwcfg2.b.hs_phy_type == 1) || + (core_if->hwcfg2.b.hs_phy_type == 3))) { + valid = 1; + } else if ((val == DWC_PHY_TYPE_PARAM_ULPI) && + ((core_if->hwcfg2.b.hs_phy_type == 2) || + (core_if->hwcfg2.b.hs_phy_type == 3))) { + valid = 1; + } else if ((val == DWC_PHY_TYPE_PARAM_FS) && + (core_if->hwcfg2.b.fs_phy_type == 1)) { + valid = 1; + } + if (!valid) { + if (dwc_otg_param_initialized(core_if->core_params->phy_type)) { + DWC_ERROR + ("%d invalid for phy_type. Check HW configurations.\n", + val); + } + if (core_if->hwcfg2.b.hs_phy_type) { + if ((core_if->hwcfg2.b.hs_phy_type == 3) || + (core_if->hwcfg2.b.hs_phy_type == 1)) { + val = DWC_PHY_TYPE_PARAM_UTMI; + } else { + val = DWC_PHY_TYPE_PARAM_ULPI; + } + } + retval = -DWC_E_INVALID; + } +#endif + core_if->core_params->phy_type = val; + return retval; +} + +int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->phy_type; +} + +int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val) +{ + int retval = 0; + if (DWC_OTG_PARAM_TEST(val, 0, 1)) { + DWC_WARN("Wrong value for speed parameter\n"); + DWC_WARN("max_speed parameter must be 0 or 1\n"); + return -DWC_E_INVALID; + } + if ((val == 0) + && dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS) { + if (dwc_otg_param_initialized(core_if->core_params->speed)) { + DWC_ERROR + ("%d invalid for speed paremter. Check HW configuration.\n", + val); + } + val = + (dwc_otg_get_param_phy_type(core_if) == + DWC_PHY_TYPE_PARAM_FS ? 1 : 0); + retval = -DWC_E_INVALID; + } + core_if->core_params->speed = val; + return retval; +} + +int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->speed; +} + +int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if, + int32_t val) +{ + int retval = 0; + + if (DWC_OTG_PARAM_TEST(val, 0, 1)) { + DWC_WARN + ("Wrong value for host_ls_low_power_phy_clk parameter\n"); + DWC_WARN("host_ls_low_power_phy_clk must be 0 or 1\n"); + return -DWC_E_INVALID; + } + + if ((val == DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ) + && (dwc_otg_get_param_phy_type(core_if) == DWC_PHY_TYPE_PARAM_FS)) { + if(dwc_otg_param_initialized(core_if->core_params->host_ls_low_power_phy_clk)) { + DWC_ERROR("%d invalid for host_ls_low_power_phy_clk. Check HW configuration.\n", + val); + } + val = + (dwc_otg_get_param_phy_type(core_if) == + DWC_PHY_TYPE_PARAM_FS) ? + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ : + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ; + retval = -DWC_E_INVALID; + } + + core_if->core_params->host_ls_low_power_phy_clk = val; + return retval; +} + +int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->host_ls_low_power_phy_clk; +} + +int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if, int32_t val) +{ + if (DWC_OTG_PARAM_TEST(val, 0, 1)) { + DWC_WARN("Wrong value for phy_ulpi_ddr\n"); + DWC_WARN("phy_upli_ddr must be 0 or 1\n"); + return -DWC_E_INVALID; + } + + core_if->core_params->phy_ulpi_ddr = val; + return 0; +} + +int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->phy_ulpi_ddr; +} + +int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if, + int32_t val) +{ + if (DWC_OTG_PARAM_TEST(val, 0, 1)) { + DWC_WARN("Wrong valaue for phy_ulpi_ext_vbus\n"); + DWC_WARN("phy_ulpi_ext_vbus must be 0 or 1\n"); + return -DWC_E_INVALID; + } + + core_if->core_params->phy_ulpi_ext_vbus = val; + return 0; +} + +int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->phy_ulpi_ext_vbus; +} + +int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if, int32_t val) +{ + if (DWC_OTG_PARAM_TEST(val, 8, 8) && DWC_OTG_PARAM_TEST(val, 16, 16)) { + DWC_WARN("Wrong valaue for phy_utmi_width\n"); + DWC_WARN("phy_utmi_width must be 8 or 16\n"); + return -DWC_E_INVALID; + } + + core_if->core_params->phy_utmi_width = val; + return 0; +} + +int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->phy_utmi_width; +} + +int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if, int32_t val) +{ + if (DWC_OTG_PARAM_TEST(val, 0, 1)) { + DWC_WARN("Wrong valaue for ulpi_fs_ls\n"); + DWC_WARN("ulpi_fs_ls must be 0 or 1\n"); + return -DWC_E_INVALID; + } + + core_if->core_params->ulpi_fs_ls = val; + return 0; +} + +int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->ulpi_fs_ls; +} + +int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val) +{ + if (DWC_OTG_PARAM_TEST(val, 0, 1)) { + DWC_WARN("Wrong valaue for ts_dline\n"); + DWC_WARN("ts_dline must be 0 or 1\n"); + return -DWC_E_INVALID; + } + + core_if->core_params->ts_dline = val; + return 0; +} + +int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->ts_dline; +} + +int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if, int32_t val) +{ + int retval = 0; + if (DWC_OTG_PARAM_TEST(val, 0, 1)) { + DWC_WARN("Wrong valaue for i2c_enable\n"); + DWC_WARN("i2c_enable must be 0 or 1\n"); + return -DWC_E_INVALID; + } +#ifndef NO_FS_PHY_HW_CHECK + if (val == 1 && core_if->hwcfg3.b.i2c == 0) { + if(dwc_otg_param_initialized(core_if->core_params->i2c_enable)) { + DWC_ERROR("%d invalid for i2c_enable. Check HW configuration.\n", + val); + } + val = 0; + retval = -DWC_E_INVALID; + } +#endif + + core_if->core_params->i2c_enable = val; + return retval; +} + +int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->i2c_enable; +} + +int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if, + int32_t val, int fifo_num) +{ + int retval = 0; + + if (DWC_OTG_PARAM_TEST(val, 4, 768)) { + DWC_WARN("Wrong value for dev_perio_tx_fifo_size\n"); + DWC_WARN("dev_perio_tx_fifo_size must be 4-768\n"); + return -DWC_E_INVALID; + } + + if (val > (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[fifo_num]))) { + if(dwc_otg_param_initialized(core_if->core_params->dev_perio_tx_fifo_size[fifo_num])) { + DWC_ERROR("`%d' invalid for parameter `dev_perio_fifo_size_%d'. Check HW configuration.\n", + val, fifo_num); + } + val = (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[fifo_num])); + retval = -DWC_E_INVALID; + } + + core_if->core_params->dev_perio_tx_fifo_size[fifo_num] = val; + return retval; +} + +int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if, + int fifo_num) +{ + return core_if->core_params->dev_perio_tx_fifo_size[fifo_num]; +} + +int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if, + int32_t val) +{ + int retval = 0; + if (DWC_OTG_PARAM_TEST(val, 0, 1)) { + DWC_WARN("Wrong valaue for en_multiple_tx_fifo,\n"); + DWC_WARN("en_multiple_tx_fifo must be 0 or 1\n"); + return -DWC_E_INVALID; + } + + if (val == 1 && core_if->hwcfg4.b.ded_fifo_en == 0) { + if(dwc_otg_param_initialized(core_if->core_params->en_multiple_tx_fifo)) { + DWC_ERROR("%d invalid for parameter en_multiple_tx_fifo. Check HW configuration.\n", + val); + } + val = 0; + retval = -DWC_E_INVALID; + } + + core_if->core_params->en_multiple_tx_fifo = val; + return retval; +} + +int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->en_multiple_tx_fifo; +} + +int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if, int32_t val, + int fifo_num) +{ + int retval = 0; + + if (DWC_OTG_PARAM_TEST(val, 4, 768)) { + DWC_WARN("Wrong value for dev_tx_fifo_size\n"); + DWC_WARN("dev_tx_fifo_size must be 4-768\n"); + return -DWC_E_INVALID; + } + + if (val > (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[fifo_num]))) { + if(dwc_otg_param_initialized(core_if->core_params->dev_tx_fifo_size[fifo_num])) { + DWC_ERROR("`%d' invalid for parameter `dev_tx_fifo_size_%d'. Check HW configuration.\n", + val, fifo_num); + } + val = (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[fifo_num])); + retval = -DWC_E_INVALID; + } + + core_if->core_params->dev_tx_fifo_size[fifo_num] = val; + return retval; +} + +int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if, + int fifo_num) +{ + return core_if->core_params->dev_tx_fifo_size[fifo_num]; +} + +int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val) +{ + int retval = 0; + + if (DWC_OTG_PARAM_TEST(val, 0, 7)) { + DWC_WARN("Wrong value for thr_ctl\n"); + DWC_WARN("thr_ctl must be 0-7\n"); + return -DWC_E_INVALID; + } + + if ((val != 0) && + (!dwc_otg_get_param_dma_enable(core_if) || + !core_if->hwcfg4.b.ded_fifo_en)) { + if(dwc_otg_param_initialized(core_if->core_params->thr_ctl)) { + DWC_ERROR("%d invalid for parameter thr_ctl. Check HW configuration.\n", + val); + } + val = 0; + retval = -DWC_E_INVALID; + } + + core_if->core_params->thr_ctl = val; + return retval; +} + +int32_t dwc_otg_get_param_thr_ctl(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->thr_ctl; +} + +int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if, int32_t val) +{ + int retval = 0; + + if (DWC_OTG_PARAM_TEST(val, 0, 1)) { + DWC_WARN("Wrong value for lpm_enable\n"); + DWC_WARN("lpm_enable must be 0 or 1\n"); + return -DWC_E_INVALID; + } + + if (val && !core_if->hwcfg3.b.otg_lpm_en) { + if(dwc_otg_param_initialized(core_if->core_params->lpm_enable)) { + DWC_ERROR("%d invalid for parameter lpm_enable. Check HW configuration.\n", + val); + } + val = 0; + retval = -DWC_E_INVALID; + } + + core_if->core_params->lpm_enable = val; + return retval; +} + +int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->lpm_enable; +} + +int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if, int32_t val) +{ + if (DWC_OTG_PARAM_TEST(val, 8, 128)) { + DWC_WARN("Wrong valaue for tx_thr_length\n"); + DWC_WARN("tx_thr_length must be 8 - 128\n"); + return -DWC_E_INVALID; + } + + core_if->core_params->tx_thr_length = val; + return 0; +} + +int32_t dwc_otg_get_param_tx_thr_length(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->tx_thr_length; +} + +int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if, int32_t val) +{ + if (DWC_OTG_PARAM_TEST(val, 8, 128)) { + DWC_WARN("Wrong valaue for rx_thr_length\n"); + DWC_WARN("rx_thr_length must be 8 - 128\n"); + return -DWC_E_INVALID; + } + + core_if->core_params->rx_thr_length = val; + return 0; +} + +int32_t dwc_otg_get_param_rx_thr_length(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->rx_thr_length; +} + +int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if, int32_t val) +{ + if (DWC_OTG_PARAM_TEST(val, 1, 1) && + DWC_OTG_PARAM_TEST(val, 4, 4) && + DWC_OTG_PARAM_TEST(val, 8, 8) && + DWC_OTG_PARAM_TEST(val, 16, 16) && + DWC_OTG_PARAM_TEST(val, 32, 32) && + DWC_OTG_PARAM_TEST(val, 64, 64) && + DWC_OTG_PARAM_TEST(val, 128, 128) && + DWC_OTG_PARAM_TEST(val, 256, 256)) { + DWC_WARN("`%d' invalid for parameter `dma_burst_size'\n", val); + return -DWC_E_INVALID; + } + core_if->core_params->dma_burst_size = val; + return 0; +} + +int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->dma_burst_size; +} + +int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if, int32_t val) +{ + int retval = 0; + if (DWC_OTG_PARAM_TEST(val, 0, 1)) { + DWC_WARN("`%d' invalid for parameter `pti_enable'\n", val); + return -DWC_E_INVALID; + } + if (val && (core_if->snpsid < OTG_CORE_REV_2_72a)) { + if (dwc_otg_param_initialized(core_if->core_params->pti_enable)) { + DWC_ERROR("%d invalid for parameter pti_enable. Check HW configuration.\n", + val); + } + retval = -DWC_E_INVALID; + val = 0; + } + core_if->core_params->pti_enable = val; + return retval; +} + +int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->pti_enable; +} + +int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if, int32_t val) +{ + int retval = 0; + if (DWC_OTG_PARAM_TEST(val, 0, 1)) { + DWC_WARN("`%d' invalid for parameter `mpi_enable'\n", val); + return -DWC_E_INVALID; + } + if (val && (core_if->hwcfg2.b.multi_proc_int == 0)) { + if (dwc_otg_param_initialized(core_if->core_params->mpi_enable)) { + DWC_ERROR("%d invalid for parameter mpi_enable. Check HW configuration.\n", + val); + } + retval = -DWC_E_INVALID; + val = 0; + } + core_if->core_params->mpi_enable = val; + return retval; +} + +int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->mpi_enable; +} + +int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if, + int32_t val) +{ + int retval = 0; + if (DWC_OTG_PARAM_TEST(val, 0, 1)) { + DWC_WARN("`%d' invalid for parameter `ic_usb_cap'\n", val); + DWC_WARN("ic_usb_cap must be 0 or 1\n"); + return -DWC_E_INVALID; + } + + if (val && (core_if->hwcfg3.b.otg_enable_ic_usb == 0)) { + if (dwc_otg_param_initialized(core_if->core_params->ic_usb_cap)) { + DWC_ERROR("%d invalid for parameter ic_usb_cap. Check HW configuration.\n", + val); + } + retval = -DWC_E_INVALID; + val = 0; + } + core_if->core_params->ic_usb_cap = val; + return retval; +} +int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->ic_usb_cap; +} + +int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if, int32_t val) +{ + int retval = 0; + int valid = 1; + + if(DWC_OTG_PARAM_TEST(val, 0, 3)) { + DWC_WARN("`%d' invalid for parameter `ahb_thr_ratio'\n", val); + DWC_WARN("ahb_thr_ratio must be 0 - 3\n"); + return -DWC_E_INVALID; + } + + if(val && (core_if->snpsid < OTG_CORE_REV_2_81a || !dwc_otg_get_param_thr_ctl(core_if))) { + valid = 0; + } else if(val && ((dwc_otg_get_param_tx_thr_length(core_if) / (1 << val)) < 4)) { + valid = 0; + } + if(valid == 0) { + if(dwc_otg_param_initialized(core_if->core_params->ahb_thr_ratio)) { + DWC_ERROR("%d invalid for parameter ahb_thr_ratio. Chack HW configuration.\n", val); + } + retval = -DWC_E_INVALID; + val = 0; + } + + core_if->core_params->ahb_thr_ratio = val; + return retval; +} +int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if) +{ + return core_if->core_params->ahb_thr_ratio; +} + + +uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if) +{ + gotgctl_data_t otgctl; + otgctl.d32 = dwc_read_reg32(&core_if->core_global_regs->gotgctl); + return otgctl.b.hstnegscs; +} + +uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if) +{ + gotgctl_data_t otgctl; + otgctl.d32 = dwc_read_reg32(&core_if->core_global_regs->gotgctl); + return otgctl.b.sesreqscs; +} + +void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val) +{ + gotgctl_data_t otgctl; + otgctl.d32 = dwc_read_reg32(&core_if->core_global_regs->gotgctl); + otgctl.b.hnpreq = val; + dwc_write_reg32(&core_if->core_global_regs->gotgctl, otgctl.d32); +} + +uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if) +{ + return core_if->snpsid; +} + +uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if) +{ + gotgctl_data_t otgctl; + otgctl.d32 = dwc_read_reg32(&core_if->core_global_regs->gotgctl); + return otgctl.b.currmod; +} + +uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if) +{ + gusbcfg_data_t usbcfg; + usbcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->gusbcfg); + return usbcfg.b.hnpcap; +} + +void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val) +{ + gusbcfg_data_t usbcfg; + usbcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->gusbcfg); + usbcfg.b.hnpcap = val; + dwc_write_reg32(&core_if->core_global_regs->gusbcfg, usbcfg.d32); +} + +uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if) +{ + gusbcfg_data_t usbcfg; + usbcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->gusbcfg); + return usbcfg.b.srpcap; +} + +void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val) +{ + gusbcfg_data_t usbcfg; + usbcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->gusbcfg); + usbcfg.b.srpcap = val; + dwc_write_reg32(&core_if->core_global_regs->gusbcfg, usbcfg.d32); +} + +uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if) +{ + dcfg_data_t dcfg; + dcfg.d32 = -1; //GRAYG + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)\n", __func__, core_if); + if (NULL == core_if) + DWC_ERROR("reg request with NULL core_if\n"); + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)->dev_if(%p)\n", __func__, + core_if, core_if->dev_if); + if (NULL == core_if->dev_if) + DWC_ERROR("reg request with NULL dev_if\n"); + DWC_DEBUGPL(DBG_CILV, "%s - core_if(%p)->dev_if(%p)->" + "dev_global_regs(%p)\n", __func__, + core_if, core_if->dev_if, + core_if->dev_if->dev_global_regs); + if (NULL == core_if->dev_if->dev_global_regs) + DWC_ERROR("reg request with NULL dev_global_regs\n"); + else { + DWC_DEBUGPL(DBG_CILV, "%s - &core_if(%p)->dev_if(%p)->" + "dev_global_regs(%p)->dcfg = %p\n", __func__, + core_if, core_if->dev_if, + core_if->dev_if->dev_global_regs, + &core_if->dev_if->dev_global_regs->dcfg); + dcfg.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dcfg); + } + return dcfg.b.devspd; +} + +void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val) +{ + dcfg_data_t dcfg; + dcfg.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dcfg); + dcfg.b.devspd = val; + dwc_write_reg32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32); +} + +uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if) +{ + hprt0_data_t hprt0; + hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0); + return hprt0.b.prtconnsts; +} + +uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if) +{ + dsts_data_t dsts; + dsts.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts); + return dsts.b.enumspd; +} + +uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if) +{ + hprt0_data_t hprt0; + hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0); + return hprt0.b.prtpwr; + +} + +void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val) +{ + hprt0_data_t hprt0; + hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0); + hprt0.b.prtpwr = val; + dwc_write_reg32(core_if->host_if->hprt0, val); +} + +uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if) +{ + hprt0_data_t hprt0; + hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0); + return hprt0.b.prtsusp; + +} + +void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val) +{ + hprt0_data_t hprt0; + hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0); + hprt0.b.prtsusp = val; + dwc_write_reg32(core_if->host_if->hprt0, val); +} + +void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val) +{ + hprt0_data_t hprt0; + hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0); + hprt0.b.prtres = val; + dwc_write_reg32(core_if->host_if->hprt0, val); +} + +uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if) +{ + dctl_data_t dctl; + dctl.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dctl); + return dctl.b.rmtwkupsig; +} + +uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if) +{ + glpmcfg_data_t lpmcfg; + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg); + + DWC_ASSERT(! + ((core_if->lx_state == DWC_OTG_L1) ^ lpmcfg.b.prt_sleep_sts), + "lx_state = %d, lmpcfg.prt_sleep_sts = %d\n", + core_if->lx_state, lpmcfg.b.prt_sleep_sts); + + return lpmcfg.b.prt_sleep_sts; +} + +uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if) +{ + glpmcfg_data_t lpmcfg; + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg); + return lpmcfg.b.rem_wkup_en; +} + +uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if) +{ + glpmcfg_data_t lpmcfg; + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg); + return lpmcfg.b.appl_resp; +} + +void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val) +{ + glpmcfg_data_t lpmcfg; + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg); + lpmcfg.b.appl_resp = val; + dwc_write_reg32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32); +} + +uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if) +{ + glpmcfg_data_t lpmcfg; + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg); + return lpmcfg.b.hsic_connect; +} + +void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val) +{ + glpmcfg_data_t lpmcfg; + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg); + lpmcfg.b.hsic_connect = val; + dwc_write_reg32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32); +} + +uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if) +{ + glpmcfg_data_t lpmcfg; + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg); + return lpmcfg.b.inv_sel_hsic; + +} + +void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val) +{ + glpmcfg_data_t lpmcfg; + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg); + lpmcfg.b.inv_sel_hsic = val; + dwc_write_reg32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32); +} + +uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if) +{ + return dwc_read_reg32(&core_if->core_global_regs->gotgctl); +} + +void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val) +{ + dwc_write_reg32(&core_if->core_global_regs->gotgctl, val); +} + +uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if) +{ + return dwc_read_reg32(&core_if->core_global_regs->gusbcfg); +} + +void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val) +{ + dwc_write_reg32(&core_if->core_global_regs->gusbcfg, val); +} + +uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if) +{ + return dwc_read_reg32(&core_if->core_global_regs->grxfsiz); +} + +void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val) +{ + dwc_write_reg32(&core_if->core_global_regs->grxfsiz, val); +} + +uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if) +{ + return dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz); +} + +void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val) +{ + dwc_write_reg32(&core_if->core_global_regs->gnptxfsiz, val); +} + +uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if) +{ + return dwc_read_reg32(&core_if->core_global_regs->gpvndctl); +} + +void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val) +{ + dwc_write_reg32(&core_if->core_global_regs->gpvndctl, val); +} + +uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if) +{ + return dwc_read_reg32(&core_if->core_global_regs->ggpio); +} + +void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val) +{ + dwc_write_reg32(&core_if->core_global_regs->ggpio, val); +} + +uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if) +{ + return dwc_read_reg32(core_if->host_if->hprt0); + +} + +void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val) +{ + dwc_write_reg32(core_if->host_if->hprt0, val); +} + +uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if) +{ + return dwc_read_reg32(&core_if->core_global_regs->guid); +} + +void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val) +{ + dwc_write_reg32(&core_if->core_global_regs->guid, val); +} + +uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if) +{ + return dwc_read_reg32(&core_if->core_global_regs->hptxfsiz); +} diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cil.h b/drivers/usb/host/dwc_otg/dwc_otg_cil.h new file mode 100644 index 000000000000..11761664dbfd --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil.h @@ -0,0 +1,1143 @@ +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil.h $ + * $Revision: #99 $ + * $Date: 2009/04/21 $ + * $Change: 1237466 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +#if !defined(__DWC_CIL_H__) +#define __DWC_CIL_H__ + +//#define HW2937_WORKAROUND +#define DBG_HW2937 0x400 + +#include "dwc_os.h" +#include "dwc_list.h" +#include "dwc_otg_dbg.h" +#include "dwc_otg_regs.h" + +#include "dwc_otg_core_if.h" + +/** + * @file + * This file contains the interface to the Core Interface Layer. + */ + +#ifdef DWC_UTE_CFI + +#define MAX_DMA_DESCS_PER_EP 256 + +/** + * Enumeration for the data buffer mode + */ +typedef enum _data_buffer_mode { + BM_STANDARD = 0, /* data buffer is in normal mode */ + BM_SG = 1, /* data buffer uses the scatter/gather mode */ + BM_CONCAT = 2, /* data buffer uses the concatenation mode */ + BM_CIRCULAR = 3, /* data buffer uses the circular DMA mode */ + BM_ALIGN = 4 /* data buffer is in buffer alignment mode */ +} data_buffer_mode_e; +#endif //DWC_UTE_CFI + +/** Macros defined for DWC OTG HW Release verison */ + +#define OTG_CORE_REV_2_60a 0x4F54260A +#define OTG_CORE_REV_2_71a 0x4F54271A +#define OTG_CORE_REV_2_72a 0x4F54272A +#define OTG_CORE_REV_2_80a 0x4F54280A +#define OTG_CORE_REV_2_81a 0x4F54281A +#define OTG_CORE_REV_2_90a 0x4F54290A + +/** + * Information for each ISOC packet. + */ +typedef struct iso_pkt_info { + uint32_t offset; + uint32_t length; + int32_t status; +} iso_pkt_info_t; + +/** + * The dwc_ep structure represents the state of a single + * endpoint when acting in device mode. It contains the data items + * needed for an endpoint to be activated and transfer packets. + */ +typedef struct dwc_ep { + /** EP number used for register address lookup */ + uint8_t num; + /** EP direction 0 = OUT */ + unsigned is_in:1; + /** EP active. */ + unsigned active:1; + + /** Periodic Tx FIFO # for IN EPs For INTR EP set to 0 to use non-periodic Tx FIFO + If dedicated Tx FIFOs are enabled for all IN Eps - Tx FIFO # FOR IN EPs*/ + unsigned tx_fifo_num:4; + /** EP type: 0 - Control, 1 - ISOC, 2 - BULK, 3 - INTR */ + unsigned type:2; +#define DWC_OTG_EP_TYPE_CONTROL 0 +#define DWC_OTG_EP_TYPE_ISOC 1 +#define DWC_OTG_EP_TYPE_BULK 2 +#define DWC_OTG_EP_TYPE_INTR 3 + + /** DATA start PID for INTR and BULK EP */ + unsigned data_pid_start:1; + /** Frame (even/odd) for ISOC EP */ + unsigned even_odd_frame:1; + /** Max Packet bytes */ + unsigned maxpacket:11; + + /** Max Transfer size */ + uint32_t maxxfer; + + /** @name Transfer state */ + /** @{ */ + + /** + * Pointer to the beginning of the transfer buffer -- do not modify + * during transfer. + */ + + dwc_dma_t dma_addr; + + dwc_dma_t dma_desc_addr; + dwc_otg_dev_dma_desc_t *desc_addr; + + uint8_t *start_xfer_buff; + /** pointer to the transfer buffer */ + uint8_t *xfer_buff; + /** Number of bytes to transfer */ + unsigned xfer_len:19; + /** Number of bytes transferred. */ + unsigned xfer_count:19; + /** Sent ZLP */ + unsigned sent_zlp:1; + /** Total len for control transfer */ + unsigned total_len:19; + + /** stall clear flag */ + unsigned stall_clear_flag:1; + +#ifdef DWC_UTE_CFI + /* The buffer mode */ + data_buffer_mode_e buff_mode; + + /* The chain of DMA descriptors. + * MAX_DMA_DESCS_PER_EP will be allocated for each active EP. + */ + dwc_otg_dma_desc_t *descs; + + /* The DMA address of the descriptors chain start */ + dma_addr_t descs_dma_addr; + /** This variable stores the length of the last enqueued request */ + uint32_t cfi_req_len; +#endif //DWC_UTE_CFI + + /** Allocated DMA Desc count */ + uint32_t desc_cnt; + +#ifdef DWC_EN_ISOC + /** + * Variables specific for ISOC EPs + * + */ + /** DMA addresses of ISOC buffers */ + dwc_dma_t dma_addr0; + dwc_dma_t dma_addr1; + + dwc_dma_t iso_dma_desc_addr; + dwc_otg_dev_dma_desc_t *iso_desc_addr; + + /** pointer to the transfer buffers */ + uint8_t *xfer_buff0; + uint8_t *xfer_buff1; + + /** number of ISOC Buffer is processing */ + uint32_t proc_buf_num; + /** Interval of ISOC Buffer processing */ + uint32_t buf_proc_intrvl; + /** Data size for regular frame */ + uint32_t data_per_frame; + + /* todo - pattern data support is to be implemented in the future */ + /** Data size for pattern frame */ + uint32_t data_pattern_frame; + /** Frame number of pattern data */ + uint32_t sync_frame; + + /** bInterval */ + uint32_t bInterval; + /** ISO Packet number per frame */ + uint32_t pkt_per_frm; + /** Next frame num for which will be setup DMA Desc */ + uint32_t next_frame; + /** Number of packets per buffer processing */ + uint32_t pkt_cnt; + /** Info for all isoc packets */ + iso_pkt_info_t *pkt_info; + /** current pkt number */ + uint32_t cur_pkt; + /** current pkt number */ + uint8_t *cur_pkt_addr; + /** current pkt number */ + uint32_t cur_pkt_dma_addr; +#endif /* DWC_EN_ISOC */ + +/** @} */ +} dwc_ep_t; + +/* + * Reasons for halting a host channel. + */ +typedef enum dwc_otg_halt_status { + DWC_OTG_HC_XFER_NO_HALT_STATUS, + DWC_OTG_HC_XFER_COMPLETE, + DWC_OTG_HC_XFER_URB_COMPLETE, + DWC_OTG_HC_XFER_ACK, + DWC_OTG_HC_XFER_NAK, + DWC_OTG_HC_XFER_NYET, + DWC_OTG_HC_XFER_STALL, + DWC_OTG_HC_XFER_XACT_ERR, + DWC_OTG_HC_XFER_FRAME_OVERRUN, + DWC_OTG_HC_XFER_BABBLE_ERR, + DWC_OTG_HC_XFER_DATA_TOGGLE_ERR, + DWC_OTG_HC_XFER_AHB_ERR, + DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE, + DWC_OTG_HC_XFER_URB_DEQUEUE +#ifdef HW2937_WORKAROUND + , DWC_OTG_HC_XFER_PAUSE_IN +#endif +} dwc_otg_halt_status_e; + +/** + * Host channel descriptor. This structure represents the state of a single + * host channel when acting in host mode. It contains the data items needed to + * transfer packets to an endpoint via a host channel. + */ +typedef struct dwc_hc { + /** Host channel number used for register address lookup */ + uint8_t hc_num; + + /** Device to access */ + unsigned dev_addr:7; + + /** EP to access */ + unsigned ep_num:4; + + /** EP direction. 0: OUT, 1: IN */ + unsigned ep_is_in:1; + + /** + * EP speed. + * One of the following values: + * - DWC_OTG_EP_SPEED_LOW + * - DWC_OTG_EP_SPEED_FULL + * - DWC_OTG_EP_SPEED_HIGH + */ + unsigned speed:2; +#define DWC_OTG_EP_SPEED_LOW 0 +#define DWC_OTG_EP_SPEED_FULL 1 +#define DWC_OTG_EP_SPEED_HIGH 2 + + /** + * Endpoint type. + * One of the following values: + * - DWC_OTG_EP_TYPE_CONTROL: 0 + * - DWC_OTG_EP_TYPE_ISOC: 1 + * - DWC_OTG_EP_TYPE_BULK: 2 + * - DWC_OTG_EP_TYPE_INTR: 3 + */ + unsigned ep_type:2; + + /** Max packet size in bytes */ + unsigned max_packet:11; + + /** + * PID for initial transaction. + * 0: DATA0,
+ * 1: DATA2,
+ * 2: DATA1,
+ * 3: MDATA (non-Control EP), + * SETUP (Control EP) + */ + unsigned data_pid_start:2; +#define DWC_OTG_HC_PID_DATA0 0 +#define DWC_OTG_HC_PID_DATA2 1 +#define DWC_OTG_HC_PID_DATA1 2 +#define DWC_OTG_HC_PID_MDATA 3 +#define DWC_OTG_HC_PID_SETUP 3 + + /** Number of periodic transactions per (micro)frame */ + unsigned multi_count:2; + + /** @name Transfer State */ + /** @{ */ + + /** Pointer to the current transfer buffer position. */ + uint8_t *xfer_buff; + /** + * In Buffer DMA mode this buffer will be used + * if xfer_buff is not DWORD aligned. + */ + dwc_dma_t align_buff; + /** Total number of bytes to transfer. */ + uint32_t xfer_len; + /** Number of bytes transferred so far. */ + uint32_t xfer_count; + /** Packet count at start of transfer.*/ + uint16_t start_pkt_count; + + /** + * Flag to indicate whether the transfer has been started. Set to 1 if + * it has been started, 0 otherwise. + */ + uint8_t xfer_started; + + /** + * Set to 1 to indicate that a PING request should be issued on this + * channel. If 0, process normally. + */ + uint8_t do_ping; + + /** + * Set to 1 to indicate that the error count for this transaction is + * non-zero. Set to 0 if the error count is 0. + */ + uint8_t error_state; + + /** + * Set to 1 to indicate that this channel should be halted the next + * time a request is queued for the channel. This is necessary in + * slave mode if no request queue space is available when an attempt + * is made to halt the channel. + */ + uint8_t halt_on_queue; + + /** + * Set to 1 if the host channel has been halted, but the core is not + * finished flushing queued requests. Otherwise 0. + */ + uint8_t halt_pending; + + /** + * Reason for halting the host channel. + */ + dwc_otg_halt_status_e halt_status; + + /* + * Split settings for the host channel + */ + uint8_t do_split; /**< Enable split for the channel */ + uint8_t complete_split; /**< Enable complete split */ + uint8_t hub_addr; /**< Address of high speed hub */ + + uint8_t port_addr; /**< Port of the low/full speed device */ + /** Split transaction position + * One of the following values: + * - DWC_HCSPLIT_XACTPOS_MID + * - DWC_HCSPLIT_XACTPOS_BEGIN + * - DWC_HCSPLIT_XACTPOS_END + * - DWC_HCSPLIT_XACTPOS_ALL */ + uint8_t xact_pos; + + /** Set when the host channel does a short read. */ + uint8_t short_read; + + /** + * Number of requests issued for this channel since it was assigned to + * the current transfer (not counting PINGs). + */ + uint8_t requests; + + /** + * Queue Head for the transfer being processed by this channel. + */ + struct dwc_otg_qh *qh; + + /** @} */ + + /** Entry in list of host channels. */ + DWC_CIRCLEQ_ENTRY(dwc_hc) hc_list_entry; + + /** @name Descriptor DMA support */ + /** @{ */ + + /** Number of Transfer Descriptors */ + uint16_t ntd; + + /** Descriptor List DMA address */ + dwc_dma_t desc_list_addr; + + /** Scheduling micro-frame bitmap. */ + uint8_t schinfo; + + /** @} */ +} dwc_hc_t; + +/** + * The following parameters may be specified when starting the module. These + * parameters define how the DWC_otg controller should be configured. + */ +typedef struct dwc_otg_core_params { + int32_t opt; + + /** + * Specifies the OTG capabilities. The driver will automatically + * detect the value for this parameter if none is specified. + * 0 - HNP and SRP capable (default) + * 1 - SRP Only capable + * 2 - No HNP/SRP capable + */ + int32_t otg_cap; + + /** + * Specifies whether to use slave or DMA mode for accessing the data + * FIFOs. The driver will automatically detect the value for this + * parameter if none is specified. + * 0 - Slave + * 1 - DMA (default, if available) + */ + int32_t dma_enable; + + /** + * When DMA mode is enabled specifies whether to use address DMA or DMA Descritor mode for accessing the data + * FIFOs in device mode. The driver will automatically detect the value for this + * parameter if none is specified. + * 0 - address DMA + * 1 - DMA Descriptor(default, if available) + */ + int32_t dma_desc_enable; + /** The DMA Burst size (applicable only for External DMA + * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32) + */ + int32_t dma_burst_size; /* Translate this to GAHBCFG values */ + + /** + * Specifies the maximum speed of operation in host and device mode. + * The actual speed depends on the speed of the attached device and + * the value of phy_type. The actual speed depends on the speed of the + * attached device. + * 0 - High Speed (default) + * 1 - Full Speed + */ + int32_t speed; + /** Specifies whether low power mode is supported when attached + * to a Full Speed or Low Speed device in host mode. + * 0 - Don't support low power mode (default) + * 1 - Support low power mode + */ + int32_t host_support_fs_ls_low_power; + + /** Specifies the PHY clock rate in low power mode when connected to a + * Low Speed device in host mode. This parameter is applicable only if + * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS + * then defaults to 6 MHZ otherwise 48 MHZ. + * + * 0 - 48 MHz + * 1 - 6 MHz + */ + int32_t host_ls_low_power_phy_clk; + + /** + * 0 - Use cC FIFO size parameters + * 1 - Allow dynamic FIFO sizing (default) + */ + int32_t enable_dynamic_fifo; + + /** Total number of 4-byte words in the data FIFO memory. This + * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic + * Tx FIFOs. + * 32 to 32768 (default 8192) + * Note: The total FIFO memory depth in the FPGA configuration is 8192. + */ + int32_t data_fifo_size; + + /** Number of 4-byte words in the Rx FIFO in device mode when dynamic + * FIFO sizing is enabled. + * 16 to 32768 (default 1064) + */ + int32_t dev_rx_fifo_size; + + /** Number of 4-byte words in the non-periodic Tx FIFO in device mode + * when dynamic FIFO sizing is enabled. + * 16 to 32768 (default 1024) + */ + int32_t dev_nperio_tx_fifo_size; + + /** Number of 4-byte words in each of the periodic Tx FIFOs in device + * mode when dynamic FIFO sizing is enabled. + * 4 to 768 (default 256) + */ + uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS]; + + /** Number of 4-byte words in the Rx FIFO in host mode when dynamic + * FIFO sizing is enabled. + * 16 to 32768 (default 1024) + */ + int32_t host_rx_fifo_size; + + /** Number of 4-byte words in the non-periodic Tx FIFO in host mode + * when Dynamic FIFO sizing is enabled in the core. + * 16 to 32768 (default 1024) + */ + int32_t host_nperio_tx_fifo_size; + + /** Number of 4-byte words in the host periodic Tx FIFO when dynamic + * FIFO sizing is enabled. + * 16 to 32768 (default 1024) + */ + int32_t host_perio_tx_fifo_size; + + /** The maximum transfer size supported in bytes. + * 2047 to 65,535 (default 65,535) + */ + int32_t max_transfer_size; + + /** The maximum number of packets in a transfer. + * 15 to 511 (default 511) + */ + int32_t max_packet_count; + + /** The number of host channel registers to use. + * 1 to 16 (default 12) + * Note: The FPGA configuration supports a maximum of 12 host channels. + */ + int32_t host_channels; + + /** The number of endpoints in addition to EP0 available for device + * mode operations. + * 1 to 15 (default 6 IN and OUT) + * Note: The FPGA configuration supports a maximum of 6 IN and OUT + * endpoints in addition to EP0. + */ + int32_t dev_endpoints; + + /** + * Specifies the type of PHY interface to use. By default, the driver + * will automatically detect the phy_type. + * + * 0 - Full Speed PHY + * 1 - UTMI+ (default) + * 2 - ULPI + */ + int32_t phy_type; + + /** + * Specifies the UTMI+ Data Width. This parameter is + * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI + * PHY_TYPE, this parameter indicates the data width between + * the MAC and the ULPI Wrapper.) Also, this parameter is + * applicable only if the OTG_HSPHY_WIDTH cC parameter was set + * to "8 and 16 bits", meaning that the core has been + * configured to work at either data path width. + * + * 8 or 16 bits (default 16) + */ + int32_t phy_utmi_width; + + /** + * Specifies whether the ULPI operates at double or single + * data rate. This parameter is only applicable if PHY_TYPE is + * ULPI. + * + * 0 - single data rate ULPI interface with 8 bit wide data + * bus (default) + * 1 - double data rate ULPI interface with 4 bit wide data + * bus + */ + int32_t phy_ulpi_ddr; + + /** + * Specifies whether to use the internal or external supply to + * drive the vbus with a ULPI phy. + */ + int32_t phy_ulpi_ext_vbus; + + /** + * Specifies whether to use the I2Cinterface for full speed PHY. This + * parameter is only applicable if PHY_TYPE is FS. + * 0 - No (default) + * 1 - Yes + */ + int32_t i2c_enable; + + int32_t ulpi_fs_ls; + + int32_t ts_dline; + + /** + * Specifies whether dedicated transmit FIFOs are + * enabled for non periodic IN endpoints in device mode + * 0 - No + * 1 - Yes + */ + int32_t en_multiple_tx_fifo; + + /** Number of 4-byte words in each of the Tx FIFOs in device + * mode when dynamic FIFO sizing is enabled. + * 4 to 768 (default 256) + */ + uint32_t dev_tx_fifo_size[MAX_TX_FIFOS]; + + /** Thresholding enable flag- + * bit 0 - enable non-ISO Tx thresholding + * bit 1 - enable ISO Tx thresholding + * bit 2 - enable Rx thresholding + */ + uint32_t thr_ctl; + + /** Thresholding length for Tx + * FIFOs in 32 bit DWORDs + */ + uint32_t tx_thr_length; + + /** Thresholding length for Rx + * FIFOs in 32 bit DWORDs + */ + uint32_t rx_thr_length; + + /** + * Specifies whether LPM (Link Power Management) support is enabled + */ + int32_t lpm_enable; + + /** Per Transfer Interrupt + * mode enable flag + * 1 - Enabled + * 0 - Disabled + */ + int32_t pti_enable; + + /** Multi Processor Interrupt + * mode enable flag + * 1 - Enabled + * 0 - Disabled + */ + int32_t mpi_enable; + + /** IS_USB Capability + * 1 - Enabled + * 0 - Disabled + */ + int32_t ic_usb_cap; + + /** AHB Threshold Ratio + * 2'b00 AHB Threshold = MAC Threshold + * 2'b01 AHB Threshold = 1/2 MAC Threshold + * 2'b10 AHB Threshold = 1/4 MAC Threshold + * 2'b11 AHB Threshold = 1/8 MAC Threshold + */ + int32_t ahb_thr_ratio; + +} dwc_otg_core_params_t; + +#ifdef DEBUG +struct dwc_otg_core_if; +typedef struct hc_xfer_info { + struct dwc_otg_core_if *core_if; + dwc_hc_t *hc; +} hc_xfer_info_t; +#endif +/* + * Device States + */ +typedef enum dwc_otg_lx_state { + /** On state */ + DWC_OTG_L0, + /** LPM sleep state*/ + DWC_OTG_L1, + /** USB suspend state*/ + DWC_OTG_L2, + /** Off state*/ + DWC_OTG_L3 +} dwc_otg_lx_state_e; + +/** + * The dwc_otg_core_if structure contains information needed to manage + * the DWC_otg controller acting in either host or device mode. It + * represents the programming view of the controller as a whole. + */ +struct dwc_otg_core_if { + /** Parameters that define how the core should be configured.*/ + dwc_otg_core_params_t *core_params; + + /** Core Global registers starting at offset 000h. */ + dwc_otg_core_global_regs_t *core_global_regs; + + /** Device-specific information */ + dwc_otg_dev_if_t *dev_if; + /** Host-specific information */ + dwc_otg_host_if_t *host_if; + + /** Value from SNPSID register */ + uint32_t snpsid; + + /* + * Set to 1 if the core PHY interface bits in USBCFG have been + * initialized. + */ + uint8_t phy_init_done; + + /* + * SRP Success flag, set by srp success interrupt in FS I2C mode + */ + uint8_t srp_success; + uint8_t srp_timer_started; + + /* Common configuration information */ + /** Power and Clock Gating Control Register */ + volatile uint32_t *pcgcctl; +#define DWC_OTG_PCGCCTL_OFFSET 0xE00 + + /** Push/pop addresses for endpoints or host channels.*/ + uint32_t *data_fifo[MAX_EPS_CHANNELS]; +#define DWC_OTG_DATA_FIFO_OFFSET 0x1000 +#define DWC_OTG_DATA_FIFO_SIZE 0x1000 + + /** Total RAM for FIFOs (Bytes) */ + uint16_t total_fifo_size; + /** Size of Rx FIFO (Bytes) */ + uint16_t rx_fifo_size; + /** Size of Non-periodic Tx FIFO (Bytes) */ + uint16_t nperio_tx_fifo_size; + + /** 1 if DMA is enabled, 0 otherwise. */ + uint8_t dma_enable; + + /** 1 if DMA descriptor is enabled, 0 otherwise. */ + uint8_t dma_desc_enable; + + /** 1 if PTI Enhancement mode is enabled, 0 otherwise. */ + uint8_t pti_enh_enable; + + /** 1 if MPI Enhancement mode is enabled, 0 otherwise. */ + uint8_t multiproc_int_enable; + + /** 1 if dedicated Tx FIFOs are enabled, 0 otherwise. */ + uint8_t en_multiple_tx_fifo; + + /** Set to 1 if multiple packets of a high-bandwidth transfer is in + * process of being queued */ + uint8_t queuing_high_bandwidth; + + /** Hardware Configuration -- stored here for convenience.*/ + hwcfg1_data_t hwcfg1; + hwcfg2_data_t hwcfg2; + hwcfg3_data_t hwcfg3; + hwcfg4_data_t hwcfg4; + + /** Host and Device Configuration -- stored here for convenience.*/ + hcfg_data_t hcfg; + dcfg_data_t dcfg; + + /** The operational State, during transations + * (a_host>>a_peripherial and b_device=>b_host) this may not + * match the core but allows the software to determine + * transitions. + */ + uint8_t op_state; + + /** + * Set to 1 if the HCD needs to be restarted on a session request + * interrupt. This is required if no connector ID status change has + * occurred since the HCD was last disconnected. + */ + uint8_t restart_hcd_on_session_req; + + /** HCD callbacks */ + /** A-Device is a_host */ +#define A_HOST (1) + /** A-Device is a_suspend */ +#define A_SUSPEND (2) + /** A-Device is a_peripherial */ +#define A_PERIPHERAL (3) + /** B-Device is operating as a Peripheral. */ +#define B_PERIPHERAL (4) + /** B-Device is operating as a Host. */ +#define B_HOST (5) + + /** HCD callbacks */ + struct dwc_otg_cil_callbacks *hcd_cb; + /** PCD callbacks */ + struct dwc_otg_cil_callbacks *pcd_cb; + + /** Device mode Periodic Tx FIFO Mask */ + uint32_t p_tx_msk; + /** Device mode Periodic Tx FIFO Mask */ + uint32_t tx_msk; + + /** Workqueue object used for handling several interrupts */ + dwc_workq_t *wq_otg; + + /** Timer object used for handling "Wakeup Detected" Interrupt */ + dwc_timer_t *wkp_timer; + +#ifdef DEBUG + uint32_t start_hcchar_val[MAX_EPS_CHANNELS]; + + hc_xfer_info_t hc_xfer_info[MAX_EPS_CHANNELS]; + dwc_timer_t *hc_xfer_timer[MAX_EPS_CHANNELS]; + + uint32_t hfnum_7_samples; + uint64_t hfnum_7_frrem_accum; + uint32_t hfnum_0_samples; + uint64_t hfnum_0_frrem_accum; + uint32_t hfnum_other_samples; + uint64_t hfnum_other_frrem_accum; +#endif + +#ifdef DWC_UTE_CFI + uint16_t pwron_rxfsiz; + uint16_t pwron_gnptxfsiz; + uint16_t pwron_txfsiz[15]; + + uint16_t init_rxfsiz; + uint16_t init_gnptxfsiz; + uint16_t init_txfsiz[15]; +#endif + + /** Lx state of device */ + dwc_otg_lx_state_e lx_state; + +}; + +#ifdef DEBUG +/* + * This function is called when transfer is timed out. + */ +extern void hc_xfer_timeout(void *ptr); +#endif + +/* + * The following functions are functions for works + * using during handling some interrupts + */ +extern void w_conn_id_status_change(void *p); + +extern void w_wakeup_detected(void *p); + +/* + * The following functions support initialization of the CIL driver component + * and the DWC_otg controller. + */ +extern void dwc_otg_core_host_init(dwc_otg_core_if_t * _core_if); +extern void dwc_otg_core_dev_init(dwc_otg_core_if_t * _core_if); + +/** @name Device CIL Functions + * The following functions support managing the DWC_otg controller in device + * mode. + */ +/**@{*/ +extern void dwc_otg_wakeup(dwc_otg_core_if_t * _core_if); +extern void dwc_otg_read_setup_packet(dwc_otg_core_if_t * _core_if, + uint32_t * _dest); +extern uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t * _core_if); +extern void dwc_otg_ep0_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep); +extern void dwc_otg_ep_activate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep); +extern void dwc_otg_ep_deactivate(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep); +extern void dwc_otg_ep_start_transfer(dwc_otg_core_if_t * _core_if, + dwc_ep_t * _ep); +extern void dwc_otg_ep_start_zl_transfer(dwc_otg_core_if_t * _core_if, + dwc_ep_t * _ep); +extern void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t * _core_if, + dwc_ep_t * _ep); +extern void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t * _core_if, + dwc_ep_t * _ep); +extern void dwc_otg_ep_write_packet(dwc_otg_core_if_t * _core_if, + dwc_ep_t * _ep, int _dma); +extern void dwc_otg_ep_set_stall(dwc_otg_core_if_t * _core_if, dwc_ep_t * _ep); +extern void dwc_otg_ep_clear_stall(dwc_otg_core_if_t * _core_if, + dwc_ep_t * _ep); +extern void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t * _core_if); + +#ifdef DWC_EN_ISOC +extern void dwc_otg_iso_ep_start_frm_transfer(dwc_otg_core_if_t * core_if, + dwc_ep_t * ep); +extern void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if, + dwc_ep_t * ep); +#endif /* DWC_EN_ISOC */ +/**@}*/ + +/** @name Host CIL Functions + * The following functions support managing the DWC_otg controller in host + * mode. + */ +/**@{*/ +extern void dwc_otg_hc_init(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc); +extern void dwc_otg_hc_halt(dwc_otg_core_if_t * _core_if, + dwc_hc_t * _hc, dwc_otg_halt_status_e _halt_status); +extern void dwc_otg_hc_cleanup(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc); +extern void dwc_otg_hc_start_transfer(dwc_otg_core_if_t * _core_if, + dwc_hc_t * _hc); +extern int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t * _core_if, + dwc_hc_t * _hc); +extern void dwc_otg_hc_do_ping(dwc_otg_core_if_t * _core_if, dwc_hc_t * _hc); +extern void dwc_otg_hc_write_packet(dwc_otg_core_if_t * _core_if, + dwc_hc_t * _hc); +extern void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t * _core_if); +extern void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t * _core_if); + +extern void dwc_otg_hc_start_transfer_ddma(dwc_otg_core_if_t * core_if, dwc_hc_t * hc); + +/* Macro used to clear one channel interrupt */ +#define clear_hc_int(_hc_regs_, _intr_) \ +do { \ + hcint_data_t hcint_clear = {.d32 = 0}; \ + hcint_clear.b._intr_ = 1; \ + dwc_write_reg32(&(_hc_regs_)->hcint, hcint_clear.d32); \ +} while (0) + +/* + * Macro used to disable one channel interrupt. Channel interrupts are + * disabled when the channel is halted or released by the interrupt handler. + * There is no need to handle further interrupts of that type until the + * channel is re-assigned. In fact, subsequent handling may cause crashes + * because the channel structures are cleaned up when the channel is released. + */ +#define disable_hc_int(_hc_regs_, _intr_) \ +do { \ + hcintmsk_data_t hcintmsk = {.d32 = 0}; \ + hcintmsk.b._intr_ = 1; \ + dwc_modify_reg32(&(_hc_regs_)->hcintmsk, hcintmsk.d32, 0); \ +} while (0) + +/** + * This function Reads HPRT0 in preparation to modify. It keeps the + * WC bits 0 so that if they are read as 1, they won't clear when you + * write it back + */ +static inline uint32_t dwc_otg_read_hprt0(dwc_otg_core_if_t * _core_if) +{ + hprt0_data_t hprt0; + hprt0.d32 = dwc_read_reg32(_core_if->host_if->hprt0); + hprt0.b.prtena = 0; + hprt0.b.prtconndet = 0; + hprt0.b.prtenchng = 0; + hprt0.b.prtovrcurrchng = 0; + return hprt0.d32; +} + +/**@}*/ + +/** @name Common CIL Functions + * The following functions support managing the DWC_otg controller in either + * device or host mode. + */ +/**@{*/ + +extern void dwc_otg_read_packet(dwc_otg_core_if_t * core_if, + uint8_t * dest, uint16_t bytes); + +extern void dwc_otg_flush_tx_fifo(dwc_otg_core_if_t * _core_if, const int _num); +extern void dwc_otg_flush_rx_fifo(dwc_otg_core_if_t * _core_if); +extern void dwc_otg_core_reset(dwc_otg_core_if_t * _core_if); + +/** + * This function returns the Core Interrupt register. + */ +static inline uint32_t dwc_otg_read_core_intr(dwc_otg_core_if_t * core_if) +{ + return (dwc_read_reg32(&core_if->core_global_regs->gintsts) & + dwc_read_reg32(&core_if->core_global_regs->gintmsk)); +} + +/** + * This function returns the OTG Interrupt register. + */ +static inline uint32_t dwc_otg_read_otg_intr(dwc_otg_core_if_t * core_if) +{ + return (dwc_read_reg32(&core_if->core_global_regs->gotgint)); +} + +/** + * This function reads the Device All Endpoints Interrupt register and + * returns the IN endpoint interrupt bits. + */ +static inline uint32_t dwc_otg_read_dev_all_in_ep_intr(dwc_otg_core_if_t * + core_if) +{ + + uint32_t v; + + if (core_if->multiproc_int_enable) { + v = dwc_read_reg32(&core_if->dev_if->dev_global_regs-> + deachint) & dwc_read_reg32(&core_if->dev_if-> + dev_global_regs-> + deachintmsk); + } else { + v = dwc_read_reg32(&core_if->dev_if->dev_global_regs->daint) & + dwc_read_reg32(&core_if->dev_if->dev_global_regs->daintmsk); + } + return (v & 0xffff); +} + +/** + * This function reads the Device All Endpoints Interrupt register and + * returns the OUT endpoint interrupt bits. + */ +static inline uint32_t dwc_otg_read_dev_all_out_ep_intr(dwc_otg_core_if_t * + core_if) +{ + uint32_t v; + + if (core_if->multiproc_int_enable) { + v = dwc_read_reg32(&core_if->dev_if->dev_global_regs-> + deachint) & dwc_read_reg32(&core_if->dev_if-> + dev_global_regs-> + deachintmsk); + } else { + v = dwc_read_reg32(&core_if->dev_if->dev_global_regs->daint) & + dwc_read_reg32(&core_if->dev_if->dev_global_regs->daintmsk); + } + + return ((v & 0xffff0000) >> 16); +} + +/** + * This function returns the Device IN EP Interrupt register + */ +static inline uint32_t dwc_otg_read_dev_in_ep_intr(dwc_otg_core_if_t * core_if, + dwc_ep_t * ep) +{ + dwc_otg_dev_if_t *dev_if = core_if->dev_if; + uint32_t v, msk, emp; + + if (core_if->multiproc_int_enable) { + msk = + dwc_read_reg32(&dev_if->dev_global_regs-> + diepeachintmsk[ep->num]); + emp = + dwc_read_reg32(&dev_if->dev_global_regs-> + dtknqr4_fifoemptymsk); + msk |= ((emp >> ep->num) & 0x1) << 7; + v = dwc_read_reg32(&dev_if->in_ep_regs[ep->num]->diepint) & msk; + } else { + msk = dwc_read_reg32(&dev_if->dev_global_regs->diepmsk); + emp = + dwc_read_reg32(&dev_if->dev_global_regs-> + dtknqr4_fifoemptymsk); + msk |= ((emp >> ep->num) & 0x1) << 7; + v = dwc_read_reg32(&dev_if->in_ep_regs[ep->num]->diepint) & msk; + } + + return v; +} + +/** + * This function returns the Device OUT EP Interrupt register + */ +static inline uint32_t dwc_otg_read_dev_out_ep_intr(dwc_otg_core_if_t * + _core_if, dwc_ep_t * _ep) +{ + dwc_otg_dev_if_t *dev_if = _core_if->dev_if; + uint32_t v; + doepmsk_data_t msk = {.d32 = 0 }; + + if (_core_if->multiproc_int_enable) { + msk.d32 = + dwc_read_reg32(&dev_if->dev_global_regs-> + doepeachintmsk[_ep->num]); + if (_core_if->pti_enh_enable) { + msk.b.pktdrpsts = 1; + } + v = dwc_read_reg32(&dev_if->out_ep_regs[_ep->num]-> + doepint) & msk.d32; + } else { + msk.d32 = dwc_read_reg32(&dev_if->dev_global_regs->doepmsk); + if (_core_if->pti_enh_enable) { + msk.b.pktdrpsts = 1; + } + v = dwc_read_reg32(&dev_if->out_ep_regs[_ep->num]-> + doepint) & msk.d32; + } + return v; +} + +/** + * This function returns the Host All Channel Interrupt register + */ +static inline uint32_t dwc_otg_read_host_all_channels_intr(dwc_otg_core_if_t * + _core_if) +{ + return (dwc_read_reg32(&_core_if->host_if->host_global_regs->haint)); +} + +static inline uint32_t dwc_otg_read_host_channel_intr(dwc_otg_core_if_t * + _core_if, dwc_hc_t * _hc) +{ + return (dwc_read_reg32 + (&_core_if->host_if->hc_regs[_hc->hc_num]->hcint)); +} + +/** + * This function returns the mode of the operation, host or device. + * + * @return 0 - Device Mode, 1 - Host Mode + */ +static inline uint32_t dwc_otg_mode(dwc_otg_core_if_t * _core_if) +{ + return (dwc_read_reg32(&_core_if->core_global_regs->gintsts) & 0x1); +} + +/**@}*/ + +/** + * DWC_otg CIL callback structure. This structure allows the HCD and + * PCD to register functions used for starting and stopping the PCD + * and HCD for role change on for a DRD. + */ +typedef struct dwc_otg_cil_callbacks { + /** Start function for role change */ + int (*start) (void *_p); + /** Stop Function for role change */ + int (*stop) (void *_p); + /** Disconnect Function for role change */ + int (*disconnect) (void *_p); + /** Resume/Remote wakeup Function */ + int (*resume_wakeup) (void *_p); + /** Suspend function */ + int (*suspend) (void *_p); + /** Session Start (SRP) */ + int (*session_start) (void *_p); +#ifdef CONFIG_USB_DWC_OTG_LPM + /** Sleep (switch to L0 state) */ + int (*sleep) (void *_p); +#endif + /** Pointer passed to start() and stop() */ + void *p; +} dwc_otg_cil_callbacks_t; + +extern void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * _core_if, + dwc_otg_cil_callbacks_t * _cb, + void *_p); +extern void dwc_otg_cil_register_hcd_callbacks(dwc_otg_core_if_t * _core_if, + dwc_otg_cil_callbacks_t * _cb, + void *_p); + +#endif diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c new file mode 100644 index 000000000000..b8b2740f992e --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c @@ -0,0 +1,846 @@ +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_cil_intr.c $ + * $Revision: #15 $ + * $Date: 2009/04/15 $ + * $Change: 1234129 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +/** @file + * + * The Core Interface Layer provides basic services for accessing and + * managing the DWC_otg hardware. These services are used by both the + * Host Controller Driver and the Peripheral Controller Driver. + * + * This file contains the Common Interrupt handlers. + */ +#include "dwc_os.h" +#include "dwc_otg_regs.h" +#include "dwc_otg_cil.h" + +#ifdef DEBUG +inline const char *op_state_str(dwc_otg_core_if_t * core_if) +{ + return (core_if->op_state == A_HOST ? "a_host" : + (core_if->op_state == A_SUSPEND ? "a_suspend" : + (core_if->op_state == A_PERIPHERAL ? "a_peripheral" : + (core_if->op_state == B_PERIPHERAL ? "b_peripheral" : + (core_if->op_state == B_HOST ? "b_host" : "unknown"))))); +} +#endif + +/** This function will log a debug message + * + * @param core_if Programming view of DWC_otg controller. + */ +int32_t dwc_otg_handle_mode_mismatch_intr(dwc_otg_core_if_t * core_if) +{ + gintsts_data_t gintsts; + DWC_WARN("Mode Mismatch Interrupt: currently in %s mode\n", + dwc_otg_mode(core_if) ? "Host" : "Device"); + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.modemismatch = 1; + dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32); + return 1; +} + +/** Start the HCD. Helper function for using the HCD callbacks. + * + * @param core_if Programming view of DWC_otg controller. + */ +static inline void hcd_start(dwc_otg_core_if_t * core_if) +{ + if (core_if->hcd_cb && core_if->hcd_cb->start) { + core_if->hcd_cb->start(core_if->hcd_cb->p); + } +} + +/** Stop the HCD. Helper function for using the HCD callbacks. + * + * @param core_if Programming view of DWC_otg controller. + */ +static inline void hcd_stop(dwc_otg_core_if_t * core_if) +{ + if (core_if->hcd_cb && core_if->hcd_cb->stop) { + core_if->hcd_cb->stop(core_if->hcd_cb->p); + } +} + +/** Disconnect the HCD. Helper function for using the HCD callbacks. + * + * @param core_if Programming view of DWC_otg controller. + */ +static inline void hcd_disconnect(dwc_otg_core_if_t * core_if) +{ + if (core_if->hcd_cb && core_if->hcd_cb->disconnect) { + core_if->hcd_cb->disconnect(core_if->hcd_cb->p); + } +} + +/** Inform the HCD the a New Session has begun. Helper function for + * using the HCD callbacks. + * + * @param core_if Programming view of DWC_otg controller. + */ +static inline void hcd_session_start(dwc_otg_core_if_t * core_if) +{ + if (core_if->hcd_cb && core_if->hcd_cb->session_start) { + core_if->hcd_cb->session_start(core_if->hcd_cb->p); + } +} + +#ifdef CONFIG_USB_DWC_OTG_LPM +/** + * Inform the HCD about LPM sleep. + * Helper function for using the HCD callbacks. + * + * @param core_if Programming view of DWC_otg controller. + */ +static inline void hcd_sleep(dwc_otg_core_if_t * core_if) +{ + if (core_if->hcd_cb && core_if->hcd_cb->sleep) { + core_if->hcd_cb->sleep(core_if->hcd_cb->p); + } +} +#endif + +/** Resume the HCD. Helper function for using the HCD callbacks. + * + * @param core_if Programming view of DWC_otg controller. + */ +static inline void hcd_resume(dwc_otg_core_if_t * core_if) +{ + if (core_if->hcd_cb && core_if->hcd_cb->resume_wakeup) { + core_if->hcd_cb->resume_wakeup(core_if->hcd_cb->p); + } +} + +/** Start the PCD. Helper function for using the PCD callbacks. + * + * @param core_if Programming view of DWC_otg controller. + */ +static inline void pcd_start(dwc_otg_core_if_t * core_if) +{ + if (core_if->pcd_cb && core_if->pcd_cb->start) { + core_if->pcd_cb->start(core_if->pcd_cb->p); + } +} + +/** Stop the PCD. Helper function for using the PCD callbacks. + * + * @param core_if Programming view of DWC_otg controller. + */ +static inline void pcd_stop(dwc_otg_core_if_t * core_if) +{ + if (core_if->pcd_cb && core_if->pcd_cb->stop) { + core_if->pcd_cb->stop(core_if->pcd_cb->p); + } +} + +/** Suspend the PCD. Helper function for using the PCD callbacks. + * + * @param core_if Programming view of DWC_otg controller. + */ +static inline void pcd_suspend(dwc_otg_core_if_t * core_if) +{ + if (core_if->pcd_cb && core_if->pcd_cb->suspend) { + core_if->pcd_cb->suspend(core_if->pcd_cb->p); + } +} + +/** Resume the PCD. Helper function for using the PCD callbacks. + * + * @param core_if Programming view of DWC_otg controller. + */ +static inline void pcd_resume(dwc_otg_core_if_t * core_if) +{ + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) { + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p); + } +} + +/** + * This function handles the OTG Interrupts. It reads the OTG + * Interrupt Register (GOTGINT) to determine what interrupt has + * occurred. + * + * @param core_if Programming view of DWC_otg controller. + */ +int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t * core_if) +{ + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; + gotgint_data_t gotgint; + gotgctl_data_t gotgctl; + gintmsk_data_t gintmsk; + + gotgint.d32 = dwc_read_reg32(&global_regs->gotgint); + gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl); + DWC_DEBUGPL(DBG_CIL, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint.d32, + op_state_str(core_if)); + + if (gotgint.b.sesenddet) { + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " + "Session End Detected++ (%s)\n", + op_state_str(core_if)); + gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl); + + if (core_if->op_state == B_HOST) { + pcd_start(core_if); + core_if->op_state = B_PERIPHERAL; + } else { + /* If not B_HOST and Device HNP still set. HNP + * Did not succeed!*/ + if (gotgctl.b.devhnpen) { + DWC_DEBUGPL(DBG_ANY, "Session End Detected\n"); + __DWC_ERROR("Device Not Connected/Responding!\n"); + } + + /* If Session End Detected the B-Cable has + * been disconnected. */ + /* Reset PCD and Gadget driver to a + * clean state. */ + core_if->lx_state = DWC_OTG_L0; + pcd_stop(core_if); + } + gotgctl.d32 = 0; + gotgctl.b.devhnpen = 1; + dwc_modify_reg32(&global_regs->gotgctl, gotgctl.d32, 0); + } + if (gotgint.b.sesreqsucstschng) { + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " + "Session Reqeust Success Status Change++\n"); + gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl); + if (gotgctl.b.sesreqscs) { + if ((core_if->core_params->phy_type == + DWC_PHY_TYPE_PARAM_FS) && (core_if->core_params->i2c_enable)) { + core_if->srp_success = 1; + } else { + pcd_resume(core_if); + /* Clear Session Request */ + gotgctl.d32 = 0; + gotgctl.b.sesreq = 1; + dwc_modify_reg32(&global_regs->gotgctl, + gotgctl.d32, 0); + } + } + } + if (gotgint.b.hstnegsucstschng) { + /* Print statements during the HNP interrupt handling + * can cause it to fail.*/ + gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl); + if (gotgctl.b.hstnegscs) { + if (dwc_otg_is_host_mode(core_if)) { + core_if->op_state = B_HOST; + /* + * Need to disable SOF interrupt immediately. + * When switching from device to host, the PCD + * interrupt handler won't handle the + * interrupt if host mode is already set. The + * HCD interrupt handler won't get called if + * the HCD state is HALT. This means that the + * interrupt does not get handled and Linux + * complains loudly. + */ + gintmsk.d32 = 0; + gintmsk.b.sofintr = 1; + dwc_modify_reg32(&global_regs->gintmsk, + gintmsk.d32, 0); + pcd_stop(core_if); + /* + * Initialize the Core for Host mode. + */ + hcd_start(core_if); + core_if->op_state = B_HOST; + } + } else { + gotgctl.d32 = 0; + gotgctl.b.hnpreq = 1; + gotgctl.b.devhnpen = 1; + dwc_modify_reg32(&global_regs->gotgctl, gotgctl.d32, 0); + DWC_DEBUGPL(DBG_ANY, "HNP Failed\n"); + __DWC_ERROR("Device Not Connected/Responding\n"); + } + } + if (gotgint.b.hstnegdet) { + /* The disconnect interrupt is set at the same time as + * Host Negotiation Detected. During the mode + * switch all interrupts are cleared so the disconnect + * interrupt handler will not get executed. + */ + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " + "Host Negotiation Detected++ (%s)\n", + (dwc_otg_is_host_mode(core_if) ? "Host" : + "Device")); + if (dwc_otg_is_device_mode(core_if)) { + DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n", + core_if->op_state); + hcd_disconnect(core_if); + pcd_start(core_if); + core_if->op_state = A_PERIPHERAL; + } else { + /* + * Need to disable SOF interrupt immediately. When + * switching from device to host, the PCD interrupt + * handler won't handle the interrupt if host mode is + * already set. The HCD interrupt handler won't get + * called if the HCD state is HALT. This means that + * the interrupt does not get handled and Linux + * complains loudly. + */ + gintmsk.d32 = 0; + gintmsk.b.sofintr = 1; + dwc_modify_reg32(&global_regs->gintmsk, gintmsk.d32, 0); + pcd_stop(core_if); + hcd_start(core_if); + core_if->op_state = A_HOST; + } + } + if (gotgint.b.adevtoutchng) { + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " + "A-Device Timeout Change++\n"); + } + if (gotgint.b.debdone) { + DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " "Debounce Done++\n"); + } + + /* Clear GOTGINT */ + dwc_write_reg32(&core_if->core_global_regs->gotgint, gotgint.d32); + + return 1; +} + +void w_conn_id_status_change(void *p) +{ + dwc_otg_core_if_t *core_if = p; + uint32_t count = 0; + gotgctl_data_t gotgctl = {.d32 = 0 }; + + gotgctl.d32 = dwc_read_reg32(&core_if->core_global_regs->gotgctl); + DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32); + DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts); + + /* B-Device connector (Device Mode) */ + if (gotgctl.b.conidsts) { + /* Wait for switch to device mode. */ + while (!dwc_otg_is_device_mode(core_if)) { + DWC_PRINTF("Waiting for Peripheral Mode, Mode=%s\n", + (dwc_otg_is_host_mode(core_if) ? "Host" : + "Peripheral")); + dwc_mdelay(100); + if (++count > 10000) + break; + } + DWC_ASSERT(++count < 10000, + "Connection id status change timed out"); + core_if->op_state = B_PERIPHERAL; + dwc_otg_core_init(core_if); + dwc_otg_enable_global_interrupts(core_if); + pcd_start(core_if); + } else { + /* A-Device connector (Host Mode) */ + while (!dwc_otg_is_host_mode(core_if)) { + DWC_PRINTF("Waiting for Host Mode, Mode=%s\n", + (dwc_otg_is_host_mode(core_if) ? "Host" : + "Peripheral")); + dwc_mdelay(100); + if (++count > 10000) + break; + } + DWC_ASSERT(++count < 10000, + "Connection id status change timed out"); + core_if->op_state = A_HOST; + /* + * Initialize the Core for Host mode. + */ + dwc_otg_core_init(core_if); + dwc_otg_enable_global_interrupts(core_if); + hcd_start(core_if); + } +} + +/** + * This function handles the Connector ID Status Change Interrupt. It + * reads the OTG Interrupt Register (GOTCTL) to determine whether this + * is a Device to Host Mode transition or a Host Mode to Device + * Transition. + * + * This only occurs when the cable is connected/removed from the PHY + * connector. + * + * @param core_if Programming view of DWC_otg controller. + */ +int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t * core_if) +{ + + /* + * Need to disable SOF interrupt immediately. If switching from device + * to host, the PCD interrupt handler won't handle the interrupt if + * host mode is already set. The HCD interrupt handler won't get + * called if the HCD state is HALT. This means that the interrupt does + * not get handled and Linux complains loudly. + */ + gintmsk_data_t gintmsk = {.d32 = 0 }; + gintsts_data_t gintsts = {.d32 = 0 }; + + gintmsk.b.sofintr = 1; + dwc_modify_reg32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0); + + DWC_DEBUGPL(DBG_CIL, + " ++Connector ID Status Change Interrupt++ (%s)\n", + (dwc_otg_is_host_mode(core_if) ? "Host" : "Device")); + + /* + * Need to schedule a work, as there are possible DELAY function calls + */ + DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change, + core_if, "connection id status change"); + + /* Set flag and clear interrupt */ + gintsts.b.conidstschng = 1; + dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32); + + return 1; +} + +/** + * This interrupt indicates that a device is initiating the Session + * Request Protocol to request the host to turn on bus power so a new + * session can begin. The handler responds by turning on bus power. If + * the DWC_otg controller is in low power mode, the handler brings the + * controller out of low power mode before turning on bus power. + * + * @param core_if Programming view of DWC_otg controller. + */ +int32_t dwc_otg_handle_session_req_intr(dwc_otg_core_if_t * core_if) +{ + hprt0_data_t hprt0; + gintsts_data_t gintsts; + +#ifndef DWC_HOST_ONLY + DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n"); + + if (dwc_otg_is_device_mode(core_if)) { + DWC_PRINTF("SRP: Device mode\n"); + } else { + DWC_PRINTF("SRP: Host mode\n"); + + /* Turn on the port power bit. */ + hprt0.d32 = dwc_otg_read_hprt0(core_if); + hprt0.b.prtpwr = 1; + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); + + /* Start the Connection timer. So a message can be displayed + * if connect does not occur within 10 seconds. */ + hcd_session_start(core_if); + } +#endif + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.sessreqintr = 1; + dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32); + + return 1; +} + +void w_wakeup_detected(void *p) +{ + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) p; + /* + * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms + * so that OPT tests pass with all PHYs). + */ + hprt0_data_t hprt0 = {.d32 = 0 }; +#if 0 + pcgcctl_data_t pcgcctl = {.d32 = 0 }; + /* Restart the Phy Clock */ + pcgcctl.b.stoppclk = 1; + dwc_modify_reg32(core_if->pcgcctl, pcgcctl.d32, 0); + dwc_udelay(10); +#endif //0 + hprt0.d32 = dwc_otg_read_hprt0(core_if); + DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32); +// dwc_mdelay(70); + hprt0.b.prtres = 0; /* Resume */ + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); + DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n", + dwc_read_reg32(core_if->host_if->hprt0)); + + hcd_resume(core_if); + + /** Change to L0 state*/ + core_if->lx_state = DWC_OTG_L0; + +} + +/** + * This interrupt indicates that the DWC_otg controller has detected a + * resume or remote wakeup sequence. If the DWC_otg controller is in + * low power mode, the handler must brings the controller out of low + * power mode. The controller automatically begins resume + * signaling. The handler schedules a time to stop resume signaling. + */ +int32_t dwc_otg_handle_wakeup_detected_intr(dwc_otg_core_if_t * core_if) +{ + gintsts_data_t gintsts; + + DWC_DEBUGPL(DBG_ANY, + "++Resume and Remote Wakeup Detected Interrupt++\n"); + + DWC_PRINTF("%s lxstate = %d\n", __func__, core_if->lx_state); + + if (dwc_otg_is_device_mode(core_if)) { + dctl_data_t dctl = {.d32 = 0 }; + DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", + dwc_read_reg32(&core_if->dev_if->dev_global_regs-> + dsts)); + if (core_if->lx_state == DWC_OTG_L2) { +#ifdef PARTIAL_POWER_DOWN + if (core_if->hwcfg4.b.power_optimiz) { + pcgcctl_data_t power = {.d32 = 0 }; + + power.d32 = dwc_read_reg32(core_if->pcgcctl); + DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n", + power.d32); + + power.b.stoppclk = 0; + dwc_write_reg32(core_if->pcgcctl, power.d32); + + power.b.pwrclmp = 0; + dwc_write_reg32(core_if->pcgcctl, power.d32); + + power.b.rstpdwnmodule = 0; + dwc_write_reg32(core_if->pcgcctl, power.d32); + } +#endif + /* Clear the Remote Wakeup Signalling */ + dctl.b.rmtwkupsig = 1; + dwc_modify_reg32(&core_if->dev_if->dev_global_regs-> + dctl, dctl.d32, 0); + + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) { + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb-> + p); + } + } else { + glpmcfg_data_t lpmcfg; + lpmcfg.d32 = + dwc_read_reg32(&core_if->core_global_regs->glpmcfg); + lpmcfg.b.hird_thres &= (~(1 << 4)); + dwc_write_reg32(&core_if->core_global_regs->glpmcfg, + lpmcfg.d32); + } + /** Change to L0 state*/ + core_if->lx_state = DWC_OTG_L0; + } else { + if (core_if->lx_state != DWC_OTG_L1) { + pcgcctl_data_t pcgcctl = {.d32 = 0 }; + + /* Restart the Phy Clock */ + pcgcctl.b.stoppclk = 1; + dwc_modify_reg32(core_if->pcgcctl, pcgcctl.d32, 0); + + DWC_TIMER_SCHEDULE(core_if->wkp_timer, 71); + } else { + /** Change to L0 state*/ + core_if->lx_state = DWC_OTG_L0; + } + } + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.wkupintr = 1; + dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32); + + return 1; +} + +/** + * This interrupt indicates that a device has been disconnected from + * the root port. + */ +int32_t dwc_otg_handle_disconnect_intr(dwc_otg_core_if_t * core_if) +{ + gintsts_data_t gintsts; + + DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n", + (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"), + op_state_str(core_if)); + +/** @todo Consolidate this if statement. */ +#ifndef DWC_HOST_ONLY + if (core_if->op_state == B_HOST) { + /* If in device mode Disconnect and stop the HCD, then + * start the PCD. */ + hcd_disconnect(core_if); + pcd_start(core_if); + core_if->op_state = B_PERIPHERAL; + } else if (dwc_otg_is_device_mode(core_if)) { + gotgctl_data_t gotgctl = {.d32 = 0 }; + gotgctl.d32 = + dwc_read_reg32(&core_if->core_global_regs->gotgctl); + if (gotgctl.b.hstsethnpen == 1) { + /* Do nothing, if HNP in process the OTG + * interrupt "Host Negotiation Detected" + * interrupt will do the mode switch. + */ + } else if (gotgctl.b.devhnpen == 0) { + /* If in device mode Disconnect and stop the HCD, then + * start the PCD. */ + hcd_disconnect(core_if); + pcd_start(core_if); + core_if->op_state = B_PERIPHERAL; + } else { + DWC_DEBUGPL(DBG_ANY, "!a_peripheral && !devhnpen\n"); + } + } else { + if (core_if->op_state == A_HOST) { + /* A-Cable still connected but device disconnected. */ + hcd_disconnect(core_if); + } + } +#endif + /* Change to L3(OFF) state */ + core_if->lx_state = DWC_OTG_L3; + + gintsts.d32 = 0; + gintsts.b.disconnect = 1; + dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32); + return 1; +} + +/** + * This interrupt indicates that SUSPEND state has been detected on + * the USB. + * + * For HNP the USB Suspend interrupt signals the change from + * "a_peripheral" to "a_host". + * + * When power management is enabled the core will be put in low power + * mode. + */ +int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t * core_if) +{ + dsts_data_t dsts; + gintsts_data_t gintsts; + + DWC_DEBUGPL(DBG_ANY, "USB SUSPEND\n"); + + if (dwc_otg_is_device_mode(core_if)) { + /* Check the Device status register to determine if the Suspend + * state is active. */ + dsts.d32 = + dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts); + DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32); + DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d " + "HWCFG4.power Optimize=%d\n", + dsts.b.suspsts, core_if->hwcfg4.b.power_optimiz); + +#ifdef PARTIAL_POWER_DOWN +/** @todo Add a module parameter for power management. */ + + if (dsts.b.suspsts && core_if->hwcfg4.b.power_optimiz) { + pcgcctl_data_t power = {.d32 = 0 }; + DWC_DEBUGPL(DBG_CIL, "suspend\n"); + + power.b.pwrclmp = 1; + dwc_write_reg32(core_if->pcgcctl, power.d32); + + power.b.rstpdwnmodule = 1; + dwc_modify_reg32(core_if->pcgcctl, 0, power.d32); + + power.b.stoppclk = 1; + dwc_modify_reg32(core_if->pcgcctl, 0, power.d32); + + } else { + DWC_DEBUGPL(DBG_ANY, "disconnect?\n"); + } +#endif + /* PCD callback for suspend. */ + pcd_suspend(core_if); + } else { + if (core_if->op_state == A_PERIPHERAL) { + DWC_DEBUGPL(DBG_ANY, "a_peripheral->a_host\n"); + /* Clear the a_peripheral flag, back to a_host. */ + pcd_stop(core_if); + hcd_start(core_if); + core_if->op_state = A_HOST; + } + } + + /* Change to L2(suspend) state */ + core_if->lx_state = DWC_OTG_L2; + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.usbsuspend = 1; + dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32); + + return 1; +} + +#ifdef CONFIG_USB_DWC_OTG_LPM +/** + * This function hadles LPM transaction received interrupt. + */ +static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t * core_if) +{ + glpmcfg_data_t lpmcfg; + gintsts_data_t gintsts; + + if (!core_if->core_params->lpm_enable) { + DWC_PRINTF("Unexpected LPM interrupt\n"); + } + + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg); + DWC_PRINTF("LPM config register = 0x%08x\n", lpmcfg.d32); + + if (dwc_otg_is_host_mode(core_if)) { + hcd_sleep(core_if); + } else { + lpmcfg.b.hird_thres |= (1 << 4); + dwc_write_reg32(&core_if->core_global_regs->glpmcfg, + lpmcfg.d32); + } + + /* Examine prt_sleep_sts after TL1TokenTetry period max (10 us) */ + dwc_udelay(10); + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg); + if (lpmcfg.b.prt_sleep_sts) { + /* Save the current state */ + core_if->lx_state = DWC_OTG_L1; + } + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.lpmtranrcvd = 1; + dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32); + return 1; +} +#endif /* CONFIG_USB_DWC_OTG_LPM */ + +/** + * This function returns the Core Interrupt register. + */ +static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if) +{ + gintsts_data_t gintsts; + gintmsk_data_t gintmsk; + gintmsk_data_t gintmsk_common = {.d32 = 0 }; + gintmsk_common.b.wkupintr = 1; + gintmsk_common.b.sessreqintr = 1; + gintmsk_common.b.conidstschng = 1; + gintmsk_common.b.otgintr = 1; + gintmsk_common.b.modemismatch = 1; + gintmsk_common.b.disconnect = 1; + gintmsk_common.b.usbsuspend = 1; +#ifdef CONFIG_USB_DWC_OTG_LPM + gintmsk_common.b.lpmtranrcvd = 1; +#endif + /** @todo: The port interrupt occurs while in device + * mode. Added code to CIL to clear the interrupt for now! + */ + gintmsk_common.b.portintr = 1; + + gintsts.d32 = dwc_read_reg32(&core_if->core_global_regs->gintsts); + gintmsk.d32 = dwc_read_reg32(&core_if->core_global_regs->gintmsk); +#ifdef DEBUG + /* if any common interrupts set */ + if (gintsts.d32 & gintmsk_common.d32) { + DWC_DEBUGPL(DBG_ANY, "gintsts=%08x gintmsk=%08x\n", + gintsts.d32, gintmsk.d32); + } +#endif + + return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32); + +} + +/** + * Common interrupt handler. + * + * The common interrupts are those that occur in both Host and Device mode. + * This handler handles the following interrupts: + * - Mode Mismatch Interrupt + * - Disconnect Interrupt + * - OTG Interrupt + * - Connector ID Status Change Interrupt + * - Session Request Interrupt. + * - Resume / Remote Wakeup Detected Interrupt. + * - LPM Transaction Received Interrutp + * + */ +int32_t dwc_otg_handle_common_intr(dwc_otg_core_if_t * core_if) +{ + int retval = 0; + gintsts_data_t gintsts; + + gintsts.d32 = dwc_otg_read_common_intr(core_if); + + if (gintsts.b.modemismatch) { + retval |= dwc_otg_handle_mode_mismatch_intr(core_if); + } + if (gintsts.b.otgintr) { + retval |= dwc_otg_handle_otg_intr(core_if); + } + if (gintsts.b.conidstschng) { + retval |= dwc_otg_handle_conn_id_status_change_intr(core_if); + } + if (gintsts.b.disconnect) { + retval |= dwc_otg_handle_disconnect_intr(core_if); + } + if (gintsts.b.sessreqintr) { + retval |= dwc_otg_handle_session_req_intr(core_if); + } + if (gintsts.b.wkupintr) { + retval |= dwc_otg_handle_wakeup_detected_intr(core_if); + } + if (gintsts.b.usbsuspend) { + retval |= dwc_otg_handle_usb_suspend_intr(core_if); + } +#ifdef CONFIG_USB_DWC_OTG_LPM + if (gintsts.b.lpmtranrcvd) { + retval |= dwc_otg_handle_lpm_intr(core_if); + } +#endif + + if (gintsts.b.portintr && dwc_otg_is_device_mode(core_if)) { + /* The port interrupt occurs while in device mode with HPRT0 + * Port Enable/Disable. + */ + gintsts.d32 = 0; + gintsts.b.portintr = 1; + dwc_write_reg32(&core_if->core_global_regs->gintsts, + gintsts.d32); + retval |= 1; + + } + return retval; +} diff --git a/drivers/usb/host/dwc_otg/dwc_otg_core_if.h b/drivers/usb/host/dwc_otg/dwc_otg_core_if.h new file mode 100644 index 000000000000..4a78b03672f9 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_core_if.h @@ -0,0 +1,641 @@ +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_core_if.h $ + * $Revision: #4 $ + * $Date: 2008/12/18 $ + * $Change: 1155299 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ +#if !defined(__DWC_CORE_IF_H__) +#define __DWC_CORE_IF_H__ + +#include "dwc_os.h" + +/** @file + * This file defines DWC_OTG Core API + */ + +struct dwc_otg_core_if; +typedef struct dwc_otg_core_if dwc_otg_core_if_t; + +/** Maximum number of Periodic FIFOs */ +#define MAX_PERIO_FIFOS 15 +/** Maximum number of Periodic FIFOs */ +#define MAX_TX_FIFOS 15 + +/** Maximum number of Endpoints/HostChannels */ +#define MAX_EPS_CHANNELS 16 + +extern dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t * _reg_base_addr); +extern void dwc_otg_core_init(dwc_otg_core_if_t * _core_if); +extern void dwc_otg_cil_remove(dwc_otg_core_if_t * _core_if); + +extern void dwc_otg_enable_global_interrupts(dwc_otg_core_if_t * _core_if); +extern void dwc_otg_disable_global_interrupts(dwc_otg_core_if_t * _core_if); + +extern uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t * _core_if); +extern uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t * _core_if); + +extern uint8_t dwc_otg_is_dma_enable(dwc_otg_core_if_t * core_if); + +/** This function should be called on every hardware interrupt. */ +extern int32_t dwc_otg_handle_common_intr(dwc_otg_core_if_t * _core_if); + +/** @name OTG Core Parameters */ +/** @{ */ + +/** + * Specifies the OTG capabilities. The driver will automatically + * detect the value for this parameter if none is specified. + * 0 - HNP and SRP capable (default) + * 1 - SRP Only capable + * 2 - No HNP/SRP capable + */ +extern int dwc_otg_set_param_otg_cap(dwc_otg_core_if_t * core_if, int32_t val); +extern int32_t dwc_otg_get_param_otg_cap(dwc_otg_core_if_t * core_if); +#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0 +#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1 +#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2 +#define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE + +extern int dwc_otg_set_param_opt(dwc_otg_core_if_t * core_if, int32_t val); +extern int32_t dwc_otg_get_param_opt(dwc_otg_core_if_t * core_if); +#define dwc_param_opt_default 1 + +/** + * Specifies whether to use slave or DMA mode for accessing the data + * FIFOs. The driver will automatically detect the value for this + * parameter if none is specified. + * 0 - Slave + * 1 - DMA (default, if available) + */ +extern int dwc_otg_set_param_dma_enable(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_dma_enable(dwc_otg_core_if_t * core_if); +#define dwc_param_dma_enable_default 1 + +/** + * When DMA mode is enabled specifies whether to use + * address DMA or DMA Descritor mode for accessing the data + * FIFOs in device mode. The driver will automatically detect + * the value for this parameter if none is specified. + * 0 - address DMA + * 1 - DMA Descriptor(default, if available) + */ +extern int dwc_otg_set_param_dma_desc_enable(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_dma_desc_enable(dwc_otg_core_if_t * core_if); +//#define dwc_param_dma_desc_enable_default 1 +#define dwc_param_dma_desc_enable_default 0 // Broadcom BCM2708 + +/** The DMA Burst size (applicable only for External DMA + * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32) + */ +extern int dwc_otg_set_param_dma_burst_size(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_dma_burst_size(dwc_otg_core_if_t * core_if); +#define dwc_param_dma_burst_size_default 32 + +/** + * Specifies the maximum speed of operation in host and device mode. + * The actual speed depends on the speed of the attached device and + * the value of phy_type. The actual speed depends on the speed of the + * attached device. + * 0 - High Speed (default) + * 1 - Full Speed + */ +extern int dwc_otg_set_param_speed(dwc_otg_core_if_t * core_if, int32_t val); +extern int32_t dwc_otg_get_param_speed(dwc_otg_core_if_t * core_if); +#define dwc_param_speed_default 0 +#define DWC_SPEED_PARAM_HIGH 0 +#define DWC_SPEED_PARAM_FULL 1 + +/** Specifies whether low power mode is supported when attached + * to a Full Speed or Low Speed device in host mode. + * 0 - Don't support low power mode (default) + * 1 - Support low power mode + */ +extern int dwc_otg_set_param_host_support_fs_ls_low_power(dwc_otg_core_if_t * + core_if, int32_t val); +extern int32_t dwc_otg_get_param_host_support_fs_ls_low_power(dwc_otg_core_if_t + * core_if); +#define dwc_param_host_support_fs_ls_low_power_default 0 + +/** Specifies the PHY clock rate in low power mode when connected to a + * Low Speed device in host mode. This parameter is applicable only if + * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS + * then defaults to 6 MHZ otherwise 48 MHZ. + * + * 0 - 48 MHz + * 1 - 6 MHz + */ +extern int dwc_otg_set_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * + core_if, int32_t val); +extern int32_t dwc_otg_get_param_host_ls_low_power_phy_clk(dwc_otg_core_if_t * + core_if); +#define dwc_param_host_ls_low_power_phy_clk_default 0 +#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0 +#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1 + +/** + * 0 - Use cC FIFO size parameters + * 1 - Allow dynamic FIFO sizing (default) + */ +extern int dwc_otg_set_param_enable_dynamic_fifo(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_enable_dynamic_fifo(dwc_otg_core_if_t * + core_if); +#define dwc_param_enable_dynamic_fifo_default 1 + +/** Total number of 4-byte words in the data FIFO memory. This + * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic + * Tx FIFOs. + * 32 to 32768 (default 8192) + * Note: The total FIFO memory depth in the FPGA configuration is 8192. + */ +extern int dwc_otg_set_param_data_fifo_size(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_data_fifo_size(dwc_otg_core_if_t * core_if); +//#define dwc_param_data_fifo_size_default 8192 +#define dwc_param_data_fifo_size_default 0xFF0 // Broadcom BCM2708 + +/** Number of 4-byte words in the Rx FIFO in device mode when dynamic + * FIFO sizing is enabled. + * 16 to 32768 (default 1064) + */ +extern int dwc_otg_set_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_dev_rx_fifo_size(dwc_otg_core_if_t * core_if); +#define dwc_param_dev_rx_fifo_size_default 1064 + +/** Number of 4-byte words in the non-periodic Tx FIFO in device mode + * when dynamic FIFO sizing is enabled. + * 16 to 32768 (default 1024) + */ +extern int dwc_otg_set_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * + core_if, int32_t val); +extern int32_t dwc_otg_get_param_dev_nperio_tx_fifo_size(dwc_otg_core_if_t * + core_if); +#define dwc_param_dev_nperio_tx_fifo_size_default 1024 + +/** Number of 4-byte words in each of the periodic Tx FIFOs in device + * mode when dynamic FIFO sizing is enabled. + * 4 to 768 (default 256) + */ +extern int dwc_otg_set_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * core_if, + int32_t val, int fifo_num); +extern int32_t dwc_otg_get_param_dev_perio_tx_fifo_size(dwc_otg_core_if_t * + core_if, int fifo_num); +#define dwc_param_dev_perio_tx_fifo_size_default 256 + +/** Number of 4-byte words in the Rx FIFO in host mode when dynamic + * FIFO sizing is enabled. + * 16 to 32768 (default 1024) + */ +extern int dwc_otg_set_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_host_rx_fifo_size(dwc_otg_core_if_t * core_if); +//#define dwc_param_host_rx_fifo_size_default 1024 +#define dwc_param_host_rx_fifo_size_default 774 // Broadcom BCM2708 + +/** Number of 4-byte words in the non-periodic Tx FIFO in host mode + * when Dynamic FIFO sizing is enabled in the core. + * 16 to 32768 (default 1024) + */ +extern int dwc_otg_set_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * + core_if, int32_t val); +extern int32_t dwc_otg_get_param_host_nperio_tx_fifo_size(dwc_otg_core_if_t * + core_if); +//#define dwc_param_host_nperio_tx_fifo_size_default 1024 +#define dwc_param_host_nperio_tx_fifo_size_default 0x100 // Broadcom BCM2708 + +/** Number of 4-byte words in the host periodic Tx FIFO when dynamic + * FIFO sizing is enabled. + * 16 to 32768 (default 1024) + */ +extern int dwc_otg_set_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * + core_if, int32_t val); +extern int32_t dwc_otg_get_param_host_perio_tx_fifo_size(dwc_otg_core_if_t * + core_if); +//#define dwc_param_host_perio_tx_fifo_size_default 1024 +#define dwc_param_host_perio_tx_fifo_size_default 0x200 // Broadcom BCM2708 + +/** The maximum transfer size supported in bytes. + * 2047 to 65,535 (default 65,535) + */ +extern int dwc_otg_set_param_max_transfer_size(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_max_transfer_size(dwc_otg_core_if_t * core_if); +#define dwc_param_max_transfer_size_default 65535 + +/** The maximum number of packets in a transfer. + * 15 to 511 (default 511) + */ +extern int dwc_otg_set_param_max_packet_count(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_max_packet_count(dwc_otg_core_if_t * core_if); +#define dwc_param_max_packet_count_default 511 + +/** The number of host channel registers to use. + * 1 to 16 (default 12) + * Note: The FPGA configuration supports a maximum of 12 host channels. + */ +extern int dwc_otg_set_param_host_channels(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_host_channels(dwc_otg_core_if_t * core_if); +#define dwc_param_host_channels_default 12 + +/** The number of endpoints in addition to EP0 available for device + * mode operations. + * 1 to 15 (default 6 IN and OUT) + * Note: The FPGA configuration supports a maximum of 6 IN and OUT + * endpoints in addition to EP0. + */ +extern int dwc_otg_set_param_dev_endpoints(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_dev_endpoints(dwc_otg_core_if_t * core_if); +#define dwc_param_dev_endpoints_default 6 + +/** + * Specifies the type of PHY interface to use. By default, the driver + * will automatically detect the phy_type. + * + * 0 - Full Speed PHY + * 1 - UTMI+ (default) + * 2 - ULPI + */ +extern int dwc_otg_set_param_phy_type(dwc_otg_core_if_t * core_if, int32_t val); +extern int32_t dwc_otg_get_param_phy_type(dwc_otg_core_if_t * core_if); +#define DWC_PHY_TYPE_PARAM_FS 0 +#define DWC_PHY_TYPE_PARAM_UTMI 1 +#define DWC_PHY_TYPE_PARAM_ULPI 2 +#define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI + +/** + * Specifies the UTMI+ Data Width. This parameter is + * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI + * PHY_TYPE, this parameter indicates the data width between + * the MAC and the ULPI Wrapper.) Also, this parameter is + * applicable only if the OTG_HSPHY_WIDTH cC parameter was set + * to "8 and 16 bits", meaning that the core has been + * configured to work at either data path width. + * + * 8 or 16 bits (default 16) + */ +extern int dwc_otg_set_param_phy_utmi_width(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_phy_utmi_width(dwc_otg_core_if_t * core_if); +//#define dwc_param_phy_utmi_width_default 16 +#define dwc_param_phy_utmi_width_default 8 // Broadcom BCM2708 + +/** + * Specifies whether the ULPI operates at double or single + * data rate. This parameter is only applicable if PHY_TYPE is + * ULPI. + * + * 0 - single data rate ULPI interface with 8 bit wide data + * bus (default) + * 1 - double data rate ULPI interface with 4 bit wide data + * bus + */ +extern int dwc_otg_set_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_phy_ulpi_ddr(dwc_otg_core_if_t * core_if); +#define dwc_param_phy_ulpi_ddr_default 0 + +/** + * Specifies whether to use the internal or external supply to + * drive the vbus with a ULPI phy. + */ +extern int dwc_otg_set_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_phy_ulpi_ext_vbus(dwc_otg_core_if_t * core_if); +#define DWC_PHY_ULPI_INTERNAL_VBUS 0 +#define DWC_PHY_ULPI_EXTERNAL_VBUS 1 +#define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS + +/** + * Specifies whether to use the I2Cinterface for full speed PHY. This + * parameter is only applicable if PHY_TYPE is FS. + * 0 - No (default) + * 1 - Yes + */ +extern int dwc_otg_set_param_i2c_enable(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_i2c_enable(dwc_otg_core_if_t * core_if); +#define dwc_param_i2c_enable_default 0 + +extern int dwc_otg_set_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_ulpi_fs_ls(dwc_otg_core_if_t * core_if); +#define dwc_param_ulpi_fs_ls_default 0 + +extern int dwc_otg_set_param_ts_dline(dwc_otg_core_if_t * core_if, int32_t val); +extern int32_t dwc_otg_get_param_ts_dline(dwc_otg_core_if_t * core_if); +#define dwc_param_ts_dline_default 0 + +/** + * Specifies whether dedicated transmit FIFOs are + * enabled for non periodic IN endpoints in device mode + * 0 - No + * 1 - Yes + */ +extern int dwc_otg_set_param_en_multiple_tx_fifo(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_en_multiple_tx_fifo(dwc_otg_core_if_t * + core_if); +#define dwc_param_en_multiple_tx_fifo_default 1 + +/** Number of 4-byte words in each of the Tx FIFOs in device + * mode when dynamic FIFO sizing is enabled. + * 4 to 768 (default 256) + */ +extern int dwc_otg_set_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if, + int fifo_num, int32_t val); +extern int32_t dwc_otg_get_param_dev_tx_fifo_size(dwc_otg_core_if_t * core_if, + int fifo_num); +#define dwc_param_dev_tx_fifo_size_default 256 + +/** Thresholding enable flag- + * bit 0 - enable non-ISO Tx thresholding + * bit 1 - enable ISO Tx thresholding + * bit 2 - enable Rx thresholding + */ +extern int dwc_otg_set_param_thr_ctl(dwc_otg_core_if_t * core_if, int32_t val); +extern int32_t dwc_otg_get_thr_ctl(dwc_otg_core_if_t * core_if, int fifo_num); +#define dwc_param_thr_ctl_default 0 + +/** Thresholding length for Tx + * FIFOs in 32 bit DWORDs + */ +extern int dwc_otg_set_param_tx_thr_length(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_tx_thr_length(dwc_otg_core_if_t * core_if); +#define dwc_param_tx_thr_length_default 64 + +/** Thresholding length for Rx + * FIFOs in 32 bit DWORDs + */ +extern int dwc_otg_set_param_rx_thr_length(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_rx_thr_length(dwc_otg_core_if_t * core_if); +#define dwc_param_rx_thr_length_default 64 + +/** + * Specifies whether LPM (Link Power Management) support is enabled + */ +extern int dwc_otg_set_param_lpm_enable(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_lpm_enable(dwc_otg_core_if_t * core_if); +#define dwc_param_lpm_enable_default 1 + +/** + * Specifies whether PTI enhancement is enabled + */ +extern int dwc_otg_set_param_pti_enable(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_pti_enable(dwc_otg_core_if_t * core_if); +#define dwc_param_pti_enable_default 0 + +/** + * Specifies whether MPI enhancement is enabled + */ +extern int dwc_otg_set_param_mpi_enable(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_mpi_enable(dwc_otg_core_if_t * core_if); +#define dwc_param_mpi_enable_default 0 + +/** + * Specifies whether IC_USB capability is enabled + */ +extern int dwc_otg_set_param_ic_usb_cap(dwc_otg_core_if_t * core_if, + int32_t val); +extern int32_t dwc_otg_get_param_ic_usb_cap(dwc_otg_core_if_t * core_if); +#define dwc_param_ic_usb_cap_default 0 + +extern int dwc_otg_set_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if, int32_t val); +extern int32_t dwc_otg_get_param_ahb_thr_ratio(dwc_otg_core_if_t * core_if); +#define dwc_param_ahb_thr_ratio_default 0 + +/** @} */ + +/** @name Access to registers and bit-fields */ + +/** + * Dump core registers and SPRAM + */ +extern void dwc_otg_dump_dev_registers(dwc_otg_core_if_t * _core_if); +extern void dwc_otg_dump_spram(dwc_otg_core_if_t * _core_if); +extern void dwc_otg_dump_host_registers(dwc_otg_core_if_t * _core_if); +extern void dwc_otg_dump_global_registers(dwc_otg_core_if_t * _core_if); + +/** + * Get host negotiation status. + */ +extern uint32_t dwc_otg_get_hnpstatus(dwc_otg_core_if_t * core_if); + +/** + * Get srp status + */ +extern uint32_t dwc_otg_get_srpstatus(dwc_otg_core_if_t * core_if); + +/** + * Set hnpreq bit in the GOTGCTL register. + */ +extern void dwc_otg_set_hnpreq(dwc_otg_core_if_t * core_if, uint32_t val); + +/** + * Get Content of SNPSID register. + */ +extern uint32_t dwc_otg_get_gsnpsid(dwc_otg_core_if_t * core_if); + +/** + * Get current mode. + * Returns 0 if in device mode, and 1 if in host mode. + */ +extern uint32_t dwc_otg_get_mode(dwc_otg_core_if_t * core_if); + +/** + * Get value of hnpcapable field in the GUSBCFG register + */ +extern uint32_t dwc_otg_get_hnpcapable(dwc_otg_core_if_t * core_if); +/** + * Set value of hnpcapable field in the GUSBCFG register + */ +extern void dwc_otg_set_hnpcapable(dwc_otg_core_if_t * core_if, uint32_t val); + +/** + * Get value of srpcapable field in the GUSBCFG register + */ +extern uint32_t dwc_otg_get_srpcapable(dwc_otg_core_if_t * core_if); +/** + * Set value of srpcapable field in the GUSBCFG register + */ +extern void dwc_otg_set_srpcapable(dwc_otg_core_if_t * core_if, uint32_t val); + +/** + * Get value of devspeed field in the DCFG register + */ +extern uint32_t dwc_otg_get_devspeed(dwc_otg_core_if_t * core_if); +/** + * Set value of devspeed field in the DCFG register + */ +extern void dwc_otg_set_devspeed(dwc_otg_core_if_t * core_if, uint32_t val); + +/** + * Get the value of busconnected field from the HPRT0 register + */ +extern uint32_t dwc_otg_get_busconnected(dwc_otg_core_if_t * core_if); + +/** + * Gets the device enumeration Speed. + */ +extern uint32_t dwc_otg_get_enumspeed(dwc_otg_core_if_t * core_if); + +/** + * Get value of prtpwr field from the HPRT0 register + */ +extern uint32_t dwc_otg_get_prtpower(dwc_otg_core_if_t * core_if); +/** + * Set value of prtpwr field from the HPRT0 register + */ +extern void dwc_otg_set_prtpower(dwc_otg_core_if_t * core_if, uint32_t val); + +/** + * Get value of prtsusp field from the HPRT0 regsiter + */ +extern uint32_t dwc_otg_get_prtsuspend(dwc_otg_core_if_t * core_if); +/** + * Set value of prtpwr field from the HPRT0 register + */ +extern void dwc_otg_set_prtsuspend(dwc_otg_core_if_t * core_if, uint32_t val); + +/** + * Set value of prtres field from the HPRT0 register + *FIXME Remove? + */ +extern void dwc_otg_set_prtresume(dwc_otg_core_if_t * core_if, uint32_t val); + +/** + * Get value of rmtwkupsig bit in DCTL register + */ +extern uint32_t dwc_otg_get_remotewakesig(dwc_otg_core_if_t * core_if); + +/** + * Get value of prt_sleep_sts field from the GLPMCFG register + */ +extern uint32_t dwc_otg_get_lpm_portsleepstatus(dwc_otg_core_if_t * core_if); + +/** + * Get value of rem_wkup_en field from the GLPMCFG register + */ +extern uint32_t dwc_otg_get_lpm_remotewakeenabled(dwc_otg_core_if_t * core_if); + +/** + * Get value of appl_resp field from the GLPMCFG register + */ +extern uint32_t dwc_otg_get_lpmresponse(dwc_otg_core_if_t * core_if); +/** + * Set value of appl_resp field from the GLPMCFG register + */ +extern void dwc_otg_set_lpmresponse(dwc_otg_core_if_t * core_if, uint32_t val); + +/** + * Get value of hsic_connect field from the GLPMCFG register + */ +extern uint32_t dwc_otg_get_hsic_connect(dwc_otg_core_if_t * core_if); +/** + * Set value of hsic_connect field from the GLPMCFG register + */ +extern void dwc_otg_set_hsic_connect(dwc_otg_core_if_t * core_if, uint32_t val); + +/** + * Get value of inv_sel_hsic field from the GLPMCFG register. + */ +extern uint32_t dwc_otg_get_inv_sel_hsic(dwc_otg_core_if_t * core_if); +/** + * Set value of inv_sel_hsic field from the GLPMFG register. + */ +extern void dwc_otg_set_inv_sel_hsic(dwc_otg_core_if_t * core_if, uint32_t val); + +/* + * Some functions for accessing registers + */ + +/** + * GOTGCTL register + */ +extern uint32_t dwc_otg_get_gotgctl(dwc_otg_core_if_t * core_if); +extern void dwc_otg_set_gotgctl(dwc_otg_core_if_t * core_if, uint32_t val); + +/** + * GUSBCFG register + */ +extern uint32_t dwc_otg_get_gusbcfg(dwc_otg_core_if_t * core_if); +extern void dwc_otg_set_gusbcfg(dwc_otg_core_if_t * core_if, uint32_t val); + +/** + * GRXFSIZ register + */ +extern uint32_t dwc_otg_get_grxfsiz(dwc_otg_core_if_t * core_if); +extern void dwc_otg_set_grxfsiz(dwc_otg_core_if_t * core_if, uint32_t val); + +/** + * GNPTXFSIZ register + */ +extern uint32_t dwc_otg_get_gnptxfsiz(dwc_otg_core_if_t * core_if); +extern void dwc_otg_set_gnptxfsiz(dwc_otg_core_if_t * core_if, uint32_t val); + +extern uint32_t dwc_otg_get_gpvndctl(dwc_otg_core_if_t * core_if); +extern void dwc_otg_set_gpvndctl(dwc_otg_core_if_t * core_if, uint32_t val); + +/** + * GGPIO register + */ +extern uint32_t dwc_otg_get_ggpio(dwc_otg_core_if_t * core_if); +extern void dwc_otg_set_ggpio(dwc_otg_core_if_t * core_if, uint32_t val); + +/** + * GUID register + */ +extern uint32_t dwc_otg_get_guid(dwc_otg_core_if_t * core_if); +extern void dwc_otg_set_guid(dwc_otg_core_if_t * core_if, uint32_t val); + +/** + * HPRT0 register + */ +extern uint32_t dwc_otg_get_hprt0(dwc_otg_core_if_t * core_if); +extern void dwc_otg_set_hprt0(dwc_otg_core_if_t * core_if, uint32_t val); + +/** + * GHPTXFSIZE + */ +extern uint32_t dwc_otg_get_hptxfsiz(dwc_otg_core_if_t * core_if); + +/** @} */ + +#endif /* __DWC_CORE_IF_H__ */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_dbg.h b/drivers/usb/host/dwc_otg/dwc_otg_dbg.h new file mode 100644 index 000000000000..e81d0935512e --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_dbg.h @@ -0,0 +1,113 @@ +/* ========================================================================== + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +#ifndef __DWC_OTG_DBG_H__ +#define __DWC_OTG_DBG_H__ + +/** @file + * This file defines debug levels. + * Debugging support vanishes in non-debug builds. + */ + +/** + * The Debug Level bit-mask variable. + */ +extern uint32_t g_dbg_lvl; +/** + * Set the Debug Level variable. + */ +static inline uint32_t SET_DEBUG_LEVEL(const uint32_t new) +{ + uint32_t old = g_dbg_lvl; + g_dbg_lvl = new; + return old; +} + +/** When debug level has the DBG_CIL bit set, display CIL Debug messages. */ +#define DBG_CIL (0x2) +/** When debug level has the DBG_CILV bit set, display CIL Verbose debug + * messages */ +#define DBG_CILV (0x20) +/** When debug level has the DBG_PCD bit set, display PCD (Device) debug + * messages */ +#define DBG_PCD (0x4) +/** When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug + * messages */ +#define DBG_PCDV (0x40) +/** When debug level has the DBG_HCD bit set, display Host debug messages */ +#define DBG_HCD (0x8) +/** When debug level has the DBG_HCDV bit set, display Verbose Host debug + * messages */ +#define DBG_HCDV (0x80) +/** When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host + * mode. */ +#define DBG_HCD_URB (0x800) + +/** When debug level has any bit set, display debug messages */ +#define DBG_ANY (0xFF) + +/** All debug messages off */ +#define DBG_OFF 0 + +/** Prefix string for DWC_DEBUG print macros. */ +#define USB_DWC "DWC_otg: " + +/** + * Print a debug message when the Global debug level variable contains + * the bit defined in lvl. + * + * @param[in] lvl - Debug level, use one of the DBG_ constants above. + * @param[in] x - like printf + * + * Example:

+ * + * DWC_DEBUGPL( DBG_ANY, "%s(%p)\n", __func__, _reg_base_addr); + * + *
+ * results in:
+ * + * usb-DWC_otg: dwc_otg_cil_init(ca867000) + * + */ +#ifdef DEBUG + +# define DWC_DEBUGPL(lvl, x...) do{ if ((lvl)&g_dbg_lvl)__DWC_DEBUG(USB_DWC x ); }while(0) +# define DWC_DEBUGP(x...) DWC_DEBUGPL(DBG_ANY, x ) + +# define CHK_DEBUG_LEVEL(level) ((level) & g_dbg_lvl) + +#else + +# define DWC_DEBUGPL(lvl, x...) do{}while(0) +# define DWC_DEBUGP(x...) + +# define CHK_DEBUG_LEVEL(level) (0) + +#endif /*DEBUG*/ +#endif diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.c b/drivers/usb/host/dwc_otg/dwc_otg_driver.c new file mode 100644 index 000000000000..0e220137d235 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c @@ -0,0 +1,1577 @@ +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.c $ + * $Revision: #76 $ + * $Date: 2009/05/03 $ + * $Change: 1245589 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +/** @file + * The dwc_otg_driver module provides the initialization and cleanup entry + * points for the DWC_otg driver. This module will be dynamically installed + * after Linux is booted using the insmod command. When the module is + * installed, the dwc_otg_driver_init function is called. When the module is + * removed (using rmmod), the dwc_otg_driver_cleanup function is called. + * + * This module also defines a data structure for the dwc_otg_driver, which is + * used in conjunction with the standard ARM lm_device structure. These + * structures allow the OTG driver to comply with the standard Linux driver + * model in which devices and drivers are registered with a bus driver. This + * has the benefit that Linux can expose attributes of the driver and device + * in its special sysfs file system. Users can then read or write files in + * this file system to perform diagnostics on the driver components or the + * device. + */ + +#include +#include +#include +#include +#include +#include +#include +#include /* permission constants */ +#include +#include + +#ifdef LM_INTERFACE +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) +#include +#include +#else +/* in 2.6.31, at least, we seem to have lost the generic LM infrastructure - + here we use definitions stolen from arm-integrator headers +*/ +#include +#include +#endif +#include +#include + +#elif defined(PLATFORM_INTERFACE) + +#include +#include + +#endif + +# include + +#include + + +#include "dwc_os.h" +#include "dwc_otg_dbg.h" +#include "dwc_otg_driver.h" +#include "dwc_otg_attr.h" +#include "dwc_otg_core_if.h" +#include "dwc_otg_pcd_if.h" +#include "dwc_otg_hcd_if.h" + +#define DWC_DRIVER_VERSION "2.90b 6-MAY-2010" +#define DWC_DRIVER_DESC "HS OTG USB Controller driver" + +static const char dwc_driver_name[] = "dwc_otg"; + +extern int pcd_init( +#ifdef LM_INTERFACE + struct lm_device *_dev +#elif defined(PCI_INTERFACE) + struct pci_dev *_dev +#elif defined(PLATFORM_INTERFACE) + struct platform_device *dev +#endif + ); +extern int hcd_init( +#ifdef LM_INTERFACE + struct lm_device *_dev +#elif defined(PCI_INTERFACE) + struct pci_dev *_dev +#elif defined(PLATFORM_INTERFACE) + struct platform_device *dev +#endif + ); + +extern int pcd_remove( +#ifdef LM_INTERFACE + struct lm_device *_dev +#elif defined(PCI_INTERFACE) + struct pci_dev *_dev +#elif defined(PLATFORM_INTERFACE) + struct platform_device *_dev +#endif + ); + +extern void hcd_remove( +#ifdef LM_INTERFACE + struct lm_device *_dev +#elif defined(PCI_INTERFACE) + struct pci_dev *_dev +#elif defined(PLATFORM_INTERFACE) + struct platform_device *_dev +#endif + ); + +/*-------------------------------------------------------------------------*/ +/* Encapsulate the module parameter settings */ + +struct dwc_otg_driver_module_params { + int32_t opt; + int32_t otg_cap; + int32_t dma_enable; + int32_t dma_desc_enable; + int32_t dma_burst_size; + int32_t speed; + int32_t host_support_fs_ls_low_power; + int32_t host_ls_low_power_phy_clk; + int32_t enable_dynamic_fifo; + int32_t data_fifo_size; + int32_t dev_rx_fifo_size; + int32_t dev_nperio_tx_fifo_size; + uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS]; + int32_t host_rx_fifo_size; + int32_t host_nperio_tx_fifo_size; + int32_t host_perio_tx_fifo_size; + int32_t max_transfer_size; + int32_t max_packet_count; + int32_t host_channels; + int32_t dev_endpoints; + int32_t phy_type; + int32_t phy_utmi_width; + int32_t phy_ulpi_ddr; + int32_t phy_ulpi_ext_vbus; + int32_t i2c_enable; + int32_t ulpi_fs_ls; + int32_t ts_dline; + int32_t en_multiple_tx_fifo; + uint32_t dev_tx_fifo_size[MAX_TX_FIFOS]; + uint32_t thr_ctl; + uint32_t tx_thr_length; + uint32_t rx_thr_length; + int32_t pti_enable; + int32_t mpi_enable; + int32_t lpm_enable; + int32_t ic_usb_cap; + int32_t ahb_thr_ratio; +}; + +static struct dwc_otg_driver_module_params dwc_otg_module_params = { + .opt = -1, + .otg_cap = -1, + .dma_enable = -1, + .dma_desc_enable = -1, + .dma_burst_size = -1, + .speed = -1, + .host_support_fs_ls_low_power = -1, + .host_ls_low_power_phy_clk = -1, + .enable_dynamic_fifo = -1, + .data_fifo_size = -1, + .dev_rx_fifo_size = -1, + .dev_nperio_tx_fifo_size = -1, + .dev_perio_tx_fifo_size = { + /* dev_perio_tx_fifo_size_1 */ + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + /* 15 */ + }, + .host_rx_fifo_size = -1, + .host_nperio_tx_fifo_size = -1, + .host_perio_tx_fifo_size = -1, + .max_transfer_size = -1, + .max_packet_count = -1, + .host_channels = -1, + .dev_endpoints = -1, + .phy_type = -1, + .phy_utmi_width = -1, + .phy_ulpi_ddr = -1, + .phy_ulpi_ext_vbus = -1, + .i2c_enable = -1, + .ulpi_fs_ls = -1, + .ts_dline = -1, + .en_multiple_tx_fifo = -1, + .dev_tx_fifo_size = { + /* dev_tx_fifo_size */ + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1 + /* 15 */ + }, + .thr_ctl = -1, + .tx_thr_length = -1, + .rx_thr_length = -1, + .pti_enable = -1, + .mpi_enable = -1, + .lpm_enable = -1, + .ic_usb_cap = -1, + .ahb_thr_ratio = -1, +}; + +/** + * This function shows the Driver Version. + */ +static ssize_t version_show(struct device_driver *dev, char *buf) +{ + return snprintf(buf, sizeof(DWC_DRIVER_VERSION) + 2, "%s\n", + DWC_DRIVER_VERSION); +} + +static DRIVER_ATTR(version, S_IRUGO, version_show, NULL); + +/** + * Global Debug Level Mask. + */ +uint32_t g_dbg_lvl = 0; /* OFF */ + +/** + * This function shows the driver Debug Level. + */ +static ssize_t dbg_level_show(struct device_driver *drv, char *buf) +{ + return sprintf(buf, "0x%0x\n", g_dbg_lvl); +} + +/** + * This function stores the driver Debug Level. + */ +static ssize_t dbg_level_store(struct device_driver *drv, const char *buf, + size_t count) +{ + g_dbg_lvl = simple_strtoul(buf, NULL, 16); + return count; +} + +static DRIVER_ATTR(debuglevel, S_IRUGO | S_IWUSR, dbg_level_show, + dbg_level_store); + +/** + * This function is called during module intialization + * to pass module parameters to the DWC_OTG CORE. + */ +static int set_parameters(dwc_otg_core_if_t * core_if) +{ + int retval = 0; + int i; + + if (dwc_otg_module_params.otg_cap != -1) { + retval += + dwc_otg_set_param_otg_cap(core_if, + dwc_otg_module_params.otg_cap); + } + if (dwc_otg_module_params.dma_enable != -1) { + retval += + dwc_otg_set_param_dma_enable(core_if, + dwc_otg_module_params. + dma_enable); + } + if (dwc_otg_module_params.dma_desc_enable != -1) { + retval += + dwc_otg_set_param_dma_desc_enable(core_if, + dwc_otg_module_params. + dma_desc_enable); + } + if (dwc_otg_module_params.opt != -1) { + retval += + dwc_otg_set_param_opt(core_if, dwc_otg_module_params.opt); + } + if (dwc_otg_module_params.dma_burst_size != -1) { + retval += + dwc_otg_set_param_dma_burst_size(core_if, + dwc_otg_module_params. + dma_burst_size); + } + if (dwc_otg_module_params.host_support_fs_ls_low_power != -1) { + retval += + dwc_otg_set_param_host_support_fs_ls_low_power(core_if, + dwc_otg_module_params. + host_support_fs_ls_low_power); + } + if (dwc_otg_module_params.enable_dynamic_fifo != -1) { + retval += + dwc_otg_set_param_enable_dynamic_fifo(core_if, + dwc_otg_module_params. + enable_dynamic_fifo); + } + if (dwc_otg_module_params.data_fifo_size != -1) { + retval += + dwc_otg_set_param_data_fifo_size(core_if, + dwc_otg_module_params. + data_fifo_size); + } + if (dwc_otg_module_params.dev_rx_fifo_size != -1) { + retval += + dwc_otg_set_param_dev_rx_fifo_size(core_if, + dwc_otg_module_params. + dev_rx_fifo_size); + } + if (dwc_otg_module_params.dev_nperio_tx_fifo_size != -1) { + retval += + dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if, + dwc_otg_module_params. + dev_nperio_tx_fifo_size); + } + if (dwc_otg_module_params.host_rx_fifo_size != -1) { + retval += + dwc_otg_set_param_host_rx_fifo_size(core_if, + dwc_otg_module_params.host_rx_fifo_size); + } + if (dwc_otg_module_params.host_nperio_tx_fifo_size != -1) { + retval += + dwc_otg_set_param_host_nperio_tx_fifo_size(core_if, + dwc_otg_module_params. + host_nperio_tx_fifo_size); + } + if (dwc_otg_module_params.host_perio_tx_fifo_size != -1) { + retval += + dwc_otg_set_param_host_perio_tx_fifo_size(core_if, + dwc_otg_module_params. + host_perio_tx_fifo_size); + } + if (dwc_otg_module_params.max_transfer_size != -1) { + retval += + dwc_otg_set_param_max_transfer_size(core_if, + dwc_otg_module_params. + max_transfer_size); + } + if (dwc_otg_module_params.max_packet_count != -1) { + retval += + dwc_otg_set_param_max_packet_count(core_if, + dwc_otg_module_params. + max_packet_count); + } + if (dwc_otg_module_params.host_channels != -1) { + retval += + dwc_otg_set_param_host_channels(core_if, + dwc_otg_module_params. + host_channels); + } + if (dwc_otg_module_params.dev_endpoints != -1) { + retval += + dwc_otg_set_param_dev_endpoints(core_if, + dwc_otg_module_params. + dev_endpoints); + } + if (dwc_otg_module_params.phy_type != -1) { + retval += + dwc_otg_set_param_phy_type(core_if, + dwc_otg_module_params.phy_type); + } + if (dwc_otg_module_params.speed != -1) { + retval += + dwc_otg_set_param_speed(core_if, + dwc_otg_module_params.speed); + } + if (dwc_otg_module_params.host_ls_low_power_phy_clk != -1) { + retval += + dwc_otg_set_param_host_ls_low_power_phy_clk(core_if, + dwc_otg_module_params. + host_ls_low_power_phy_clk); + } + if (dwc_otg_module_params.phy_ulpi_ddr != -1) { + retval += + dwc_otg_set_param_phy_ulpi_ddr(core_if, + dwc_otg_module_params. + phy_ulpi_ddr); + } + if (dwc_otg_module_params.phy_ulpi_ext_vbus != -1) { + retval += + dwc_otg_set_param_phy_ulpi_ext_vbus(core_if, + dwc_otg_module_params. + phy_ulpi_ext_vbus); + } + if (dwc_otg_module_params.phy_utmi_width != -1) { + retval += + dwc_otg_set_param_phy_utmi_width(core_if, + dwc_otg_module_params. + phy_utmi_width); + } + if (dwc_otg_module_params.ulpi_fs_ls != -1) { + retval += + dwc_otg_set_param_ulpi_fs_ls(core_if, dwc_otg_module_params.ulpi_fs_ls); + } + if (dwc_otg_module_params.ts_dline != -1) { + retval += + dwc_otg_set_param_ts_dline(core_if, + dwc_otg_module_params.ts_dline); + } + if (dwc_otg_module_params.i2c_enable != -1) { + retval += + dwc_otg_set_param_i2c_enable(core_if, + dwc_otg_module_params. + i2c_enable); + } + if (dwc_otg_module_params.en_multiple_tx_fifo != -1) { + retval += + dwc_otg_set_param_en_multiple_tx_fifo(core_if, + dwc_otg_module_params. + en_multiple_tx_fifo); + } + for (i = 0; i < 15; i++) { + if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] != -1) { + retval += + dwc_otg_set_param_dev_perio_tx_fifo_size(core_if, + dwc_otg_module_params. + dev_perio_tx_fifo_size + [i], i); + } + } + + for (i = 0; i < 15; i++) { + if (dwc_otg_module_params.dev_tx_fifo_size[i] != -1) { + retval += dwc_otg_set_param_dev_tx_fifo_size(core_if, + dwc_otg_module_params. + dev_tx_fifo_size + [i], i); + } + } + if (dwc_otg_module_params.thr_ctl != -1) { + retval += + dwc_otg_set_param_thr_ctl(core_if, + dwc_otg_module_params.thr_ctl); + } + if (dwc_otg_module_params.mpi_enable != -1) { + retval += + dwc_otg_set_param_mpi_enable(core_if, + dwc_otg_module_params. + mpi_enable); + } + if (dwc_otg_module_params.pti_enable != -1) { + retval += + dwc_otg_set_param_pti_enable(core_if, + dwc_otg_module_params. + pti_enable); + } + if (dwc_otg_module_params.lpm_enable != -1) { + retval += + dwc_otg_set_param_lpm_enable(core_if, + dwc_otg_module_params. + lpm_enable); + } + if (dwc_otg_module_params.ic_usb_cap != -1) { + retval += + dwc_otg_set_param_ic_usb_cap(core_if, + dwc_otg_module_params. + ic_usb_cap); + } + if (dwc_otg_module_params.tx_thr_length != -1) { + retval += + dwc_otg_set_param_tx_thr_length(core_if, + dwc_otg_module_params.tx_thr_length); + } + if (dwc_otg_module_params.rx_thr_length != -1) { + retval += + dwc_otg_set_param_rx_thr_length(core_if, + dwc_otg_module_params. + rx_thr_length); + } + if(dwc_otg_module_params.ahb_thr_ratio != -1) { + retval += + dwc_otg_set_param_ahb_thr_ratio(core_if, dwc_otg_module_params.ahb_thr_ratio); + } + return retval; +} + +/** + * This function is the top level interrupt handler for the Common + * (Device and host modes) interrupts. + */ +static irqreturn_t dwc_otg_common_irq(int irq, void *dev) +{ + dwc_otg_device_t *otg_dev = dev; + int32_t retval = IRQ_NONE; + + retval = dwc_otg_handle_common_intr(otg_dev->core_if); + if (retval != 0) { + S3C2410X_CLEAR_EINTPEND(); + } + return IRQ_RETVAL(retval); +} + +/** + * This function is called when a lm_device is unregistered with the + * dwc_otg_driver. This happens, for example, when the rmmod command is + * executed. The device may or may not be electrically present. If it is + * present, the driver stops device processing. Any resources used on behalf + * of this device are freed. + * + * @param _dev + */ +#ifdef LM_INTERFACE +static void dwc_otg_driver_remove( + struct lm_device *_dev +#elif defined(PCI_INTERFACE) +static void dwc_otg_driver_remove( + struct pci_dev *_dev +#elif defined(PLATFORM_INTERFACE) +static int dwc_otg_driver_remove( + struct platform_device *_dev +#endif +) + +{ +#ifdef LM_INTERFACE + dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev); +#endif + + + DWC_DEBUGPL(DBG_ANY, "%s(%p) otg_dev %p\n", __func__, _dev, otg_dev); + + if (!otg_dev) { + /* Memory allocation for the dwc_otg_device failed. */ + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__); +#ifdef PLATFORM_INTERFACE + return -ENOMEM; +#else + return; +#endif + } +#ifndef DWC_DEVICE_ONLY + if (otg_dev->hcd) { + hcd_remove(_dev); + } else { + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__); +#ifdef PLATFORM_INTERFACE + return -EINVAL; +#else + return; +#endif + } +#endif + +#ifndef DWC_HOST_ONLY + if (otg_dev->pcd) { + pcd_remove(_dev); + } +#endif + /* + * Free the IRQ + */ + if (otg_dev->common_irq_installed) { +#ifdef PLATFORM_INTERFACE + free_irq(platform_get_irq(_dev, 0), otg_dev); +#else + free_irq(_dev->irq, otg_dev); +#endif + } + + if (otg_dev->core_if) { + dwc_otg_cil_remove(otg_dev->core_if); + } + + /* + * Remove the device attributes + */ + dwc_otg_attr_remove(_dev); + + /* + * Return the memory. + */ + if (otg_dev->base) { + iounmap(otg_dev->base); + } + dwc_free(otg_dev); + + /* + * Clear the drvdata pointer. + */ +#ifdef LM_INTERFACE + lm_set_drvdata(_dev, 0); +#elif defined(PCI_INTERFACE) + release_mem_region(otg_dev->rsrc_start, otg_dev->rsrc_len); + pci_set_drvdata(_dev, 0); +#elif defined(PLATFORM_INTERFACE) + platform_set_drvdata(_dev, 0); + return 0; +#endif +} + +/** + * This function is called when an lm_device is bound to a + * dwc_otg_driver. It creates the driver components required to + * control the device (CIL, HCD, and PCD) and it initializes the + * device. The driver components are stored in a dwc_otg_device + * structure. A reference to the dwc_otg_device is saved in the + * lm_device. This allows the driver to access the dwc_otg_device + * structure on subsequent calls to driver methods for this device. + * + * @param _dev Bus device + */ +static int dwc_otg_driver_probe( +#ifdef LM_INTERFACE +struct lm_device *_dev +#elif defined(PCI_INTERFACE) +struct pci_dev *_dev, const struct pci_device_id *id +#elif defined(PLATFORM_INTERFACE) +struct platform_device *_dev +#endif +) +{ + int retval = 0; + dwc_otg_device_t *dwc_otg_device; + int devirq; + + dev_dbg(&_dev->dev, "dwc_otg_driver_probe(%p)\n", _dev); +#ifdef LM_INTERFACE + dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)_dev->resource.start); +#elif defined(PCI_INTERFACE) + if (!id) { + DWC_ERROR("Invalid pci_device_id %p", id); + return -EINVAL; + } + + if (!_dev || (pci_enable_device(_dev) < 0)) { + DWC_ERROR("Invalid pci_device %p", _dev); + return -ENODEV; + } + dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)pci_resource_start(_dev,0)); + /* other stuff needed as well? */ + +#elif defined(PLATFORM_INTERFACE) + dev_dbg(&_dev->dev, "start=0x%08x (len 0x%x)\n", + (unsigned)_dev->resource->start, + (unsigned)(_dev->resource->end - _dev->resource->start)); +#endif + + + dwc_otg_device = dwc_alloc(sizeof(dwc_otg_device_t)); + + if (!dwc_otg_device) { + dev_err(&_dev->dev, "kmalloc of dwc_otg_device failed\n"); + retval = -ENOMEM; + goto fail; + } + + memset(dwc_otg_device, 0, sizeof(*dwc_otg_device)); + dwc_otg_device->reg_offset = 0xFFFFFFFF; + + /* + * Map the DWC_otg Core memory into virtual address space. + */ +#ifdef LM_INTERFACE +#if 1 + dwc_otg_device->base = ioremap(_dev->resource.start, SZ_256K); +#else + struct map_desc desc = { + .virtual = IO_ADDRESS((unsigned)_dev->resource.start), + .pfn = __phys_to_pfn((unsigned)_dev->resource.start), + .length = SZ_128K, + .type = MT_DEVICE + }; + iotable_init(&desc, 1); + dwc_otg_device->base = (void *)desc.virtual; +#endif + + if (!dwc_otg_device->base) { + dev_err(&_dev->dev, "ioremap() failed\n"); + retval = -ENOMEM; + goto fail; + } + dev_dbg(&_dev->dev, "base=0x%08x\n", (unsigned)dwc_otg_device->base); +#elif defined(PCI_INTERFACE) + _dev->current_state = PCI_D0; + _dev->dev.power.power_state = PMSG_ON; + + if (!_dev->irq) { + DWC_ERROR("Found HC with no IRQ. Check BIOS/PCI %s setup!", pci_name(_dev)); + retval = -ENODEV; + goto fail; + } + + dwc_otg_device->rsrc_start = pci_resource_start(_dev,0); + dwc_otg_device->rsrc_len = pci_resource_len(_dev,0); + DWC_DEBUGPL(DBG_ANY,"PCI resource: start=%08x, len=%08x\n", + dwc_otg_device->rsrc_start, + dwc_otg_device->rsrc_len); + if (!request_mem_region(dwc_otg_device->rsrc_start, dwc_otg_device->rsrc_len, "dwc_otg")) { + dev_dbg(&_dev->dev, "error mapping memory\n"); + retval = -EFAULT; + goto fail; + } + + dwc_otg_device->base = ioremap_nocache(dwc_otg_device->rsrc_start, dwc_otg_device->rsrc_len); + if (dwc_otg_device->base == NULL) { + dev_dbg(&_dev->dev, "error mapping memory\n"); + retval = -EFAULT; + goto fail; + } + dev_dbg(&_dev->dev, "base=0x%p (before adjust) \n", dwc_otg_device->base); + dwc_otg_device->base = (char *)dwc_otg_device->base; + dev_dbg(&_dev->dev, "base=0x%p (after adjust) \n", dwc_otg_device->base); + dev_dbg(&_dev->dev, "%s: mapped PA 0x%x to VA 0x%p\n", __func__, + (unsigned)dwc_otg_device->rsrc_start, dwc_otg_device->base); + // + pci_set_drvdata(_dev, dwc_otg_device); + pci_set_master(_dev); +#elif defined(PLATFORM_INTERFACE) + DWC_DEBUGPL(DBG_ANY,"Platform resource: start=%08x, len=%08x\n", + _dev->resource->start, + _dev->resource->end - _dev->resource->start + 1); +#if 1 + if (!request_mem_region(_dev->resource->start, + _dev->resource->end - _dev->resource->start + 1, + "dwc_otg")) { + dev_dbg(&_dev->dev, "error reserving mapped memory\n"); + retval = -EFAULT; + goto fail; + } + + dwc_otg_device->base = ioremap_nocache(_dev->resource->start, + _dev->resource->end - + _dev->resource->start + 1); +#else + { + struct map_desc desc = { + .virtual = IO_ADDRESS((unsigned)_dev->resource->start), + .pfn = __phys_to_pfn((unsigned)_dev->resource->start), + .length = SZ_128K, + .type = MT_DEVICE + }; + iotable_init(&desc, 1); + dwc_otg_device->base = (void *)desc.virtual; + } +#endif + if (!dwc_otg_device->base) { + dev_err(&_dev->dev, "ioremap() failed\n"); + retval = -ENOMEM; + goto fail; + } + dev_dbg(&_dev->dev, "base=0x%08x\n", (unsigned)dwc_otg_device->base); +#endif + + /* + * Initialize driver data to point to the global DWC_otg + * Device structure. + */ +#ifdef LM_INTERFACE + lm_set_drvdata(_dev, dwc_otg_device); +#elif defined(PLATFORM_INTERFACE) + platform_set_drvdata(_dev, dwc_otg_device); +#endif + dev_dbg(&_dev->dev, "dwc_otg_device=0x%p\n", dwc_otg_device); + + dwc_otg_device->core_if = dwc_otg_cil_init(dwc_otg_device->base); + DWC_DEBUGPL(DBG_HCDV, "probe of device %p given core_if %p\n", + dwc_otg_device, dwc_otg_device->core_if);//GRAYG + + if (!dwc_otg_device->core_if) { + dev_err(&_dev->dev, "CIL initialization failed!\n"); + retval = -ENOMEM; + goto fail; + } + + dev_dbg(&_dev->dev, "Calling get_gsnpsid\n"); + /* + * Attempt to ensure this device is really a DWC_otg Controller. + * Read and verify the SNPSID register contents. The value should be + * 0x45F42XXX, which corresponds to "OT2", as in "OTG version 2.XX". + */ + + if ((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) != + 0x4F542000) { + dev_err(&_dev->dev, "Bad value for SNPSID: 0x%08x\n", + dwc_otg_get_gsnpsid(dwc_otg_device->core_if)); + dwc_otg_cil_remove(dwc_otg_device->core_if); + dwc_free(dwc_otg_device); + retval = -EINVAL; + goto fail; + } + + /* + * Validate parameter values. + */ + dev_dbg(&_dev->dev, "Calling set_parameters\n"); + if (set_parameters(dwc_otg_device->core_if)) { + dwc_otg_cil_remove(dwc_otg_device->core_if); + retval = -EINVAL; + goto fail; + } + + /* + * Create Device Attributes in sysfs + */ + dev_dbg(&_dev->dev, "Calling attr_create\n"); + dwc_otg_attr_create(_dev); + + /* + * Disable the global interrupt until all the interrupt + * handlers are installed. + */ + dev_dbg(&_dev->dev, "Calling disable_global_interrupts\n"); + dwc_otg_disable_global_interrupts(dwc_otg_device->core_if); + + /* + * Install the interrupt handler for the common interrupts before + * enabling common interrupts in core_init below. + */ +#if defined(PLATFORM_INTERFACE) + devirq = platform_get_irq(_dev, 0); +#else + devirq = _dev->irq; +#endif + DWC_DEBUGPL(DBG_CIL, "registering (common) handler for irq%d\n", + devirq); + dev_dbg(&_dev->dev, "Calling request_irq(%d)\n", devirq); + retval = request_irq(devirq, dwc_otg_common_irq, + IRQF_SHARED, + "dwc_otg", dwc_otg_device); + if (retval) { + DWC_ERROR("request of irq%d failed\n", devirq); + retval = -EBUSY; + goto fail; + } else { + dwc_otg_device->common_irq_installed = 1; + } + +#ifndef IRQF_TRIGGER_LOW +#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE) + dev_dbg(&_dev->dev, "Calling set_irq_type\n"); + set_irq_type(devirq, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) + IRQT_LOW +#else + IRQ_TYPE_LEVEL_LOW +#endif + ); +#endif +#endif /*IRQF_TRIGGER_LOW*/ + + /* + * Initialize the DWC_otg core. + */ + dev_dbg(&_dev->dev, "Calling dwc_otg_core_init\n"); + dwc_otg_core_init(dwc_otg_device->core_if); + +#ifndef DWC_HOST_ONLY + /* + * Initialize the PCD + */ + dev_dbg(&_dev->dev, "Calling pcd_init\n"); + retval = pcd_init(_dev); + if (retval != 0) { + DWC_ERROR("pcd_init failed\n"); + dwc_otg_device->pcd = NULL; + goto fail; + } +#endif +#ifndef DWC_DEVICE_ONLY + /* + * Initialize the HCD + */ + dev_dbg(&_dev->dev, "Calling hcd_init\n"); + retval = hcd_init(_dev); + if (retval != 0) { + DWC_ERROR("hcd_init failed\n"); + dwc_otg_device->hcd = NULL; + goto fail; + } +#endif + /* Recover from drvdata having been overwritten by hcd_init() */ +#ifdef LM_INTERFACE + lm_set_drvdata(_dev, dwc_otg_device); +#elif defined(PLATFORM_INTERFACE) + platform_set_drvdata(_dev, dwc_otg_device); +#elif defined(PCI_INTERFACE) + pci_set_drvdata(_dev, dwc_otg_device); +#endif + + /* + * Enable the global interrupt after all the interrupt + * handlers are installed. + */ + dev_dbg(&_dev->dev, "Calling enable_global_interrupts\n"); + dwc_otg_enable_global_interrupts(dwc_otg_device->core_if); + dev_dbg(&_dev->dev, "Done\n"); + + return 0; + + fail: + dwc_otg_driver_remove(_dev); + return retval; +} + +/** + * This structure defines the methods to be called by a bus driver + * during the lifecycle of a device on that bus. Both drivers and + * devices are registered with a bus driver. The bus driver matches + * devices to drivers based on information in the device and driver + * structures. + * + * The probe function is called when the bus driver matches a device + * to this driver. The remove function is called when a device is + * unregistered with the bus driver. + */ +#ifdef LM_INTERFACE +static struct lm_driver dwc_otg_driver = { + .drv = { + .name = (char *)dwc_driver_name, + }, + .probe = dwc_otg_driver_probe, + .remove = dwc_otg_driver_remove, + // 'suspend' and 'resume' absent +}; +#elif defined(PCI_INTERFACE) +static const struct pci_device_id pci_ids[] = { { + PCI_DEVICE(0x16c3, 0xabcd), + .driver_data = (unsigned long) 0xdeadbeef, + }, { /* end: all zeroes */ } +}; +MODULE_DEVICE_TABLE(pci, pci_ids); + +/* pci driver glue; this is a "new style" PCI driver module */ +static struct pci_driver dwc_otg_driver = { + .name = "dwc_otg", + .id_table = pci_ids, + + .probe = dwc_otg_driver_probe, + .remove = dwc_otg_driver_remove, + + .driver = { + .name = (char*)dwc_driver_name, + }, +}; +#elif defined(PLATFORM_INTERFACE) +static struct platform_device_id platform_ids[] = { + { + .name = "bcm2708_usb", + .driver_data = (kernel_ulong_t) 0xdeadbeef, + }, + { /* end: all zeroes */ } +}; +MODULE_DEVICE_TABLE(platform, platform_ids); + +static struct platform_driver dwc_otg_driver = { + .driver = { + .name = (char *)dwc_driver_name, + }, + .id_table = platform_ids, + + .probe = dwc_otg_driver_probe, + .remove = dwc_otg_driver_remove, + // no 'shutdown', 'suspend', 'resume', 'suspend_late' or 'resume_early' +}; +#endif + + +/** + * This function is called when the dwc_otg_driver is installed with the + * insmod command. It registers the dwc_otg_driver structure with the + * appropriate bus driver. This will cause the dwc_otg_driver_probe function + * to be called. In addition, the bus driver will automatically expose + * attributes defined for the device and driver in the special sysfs file + * system. + * + * @return + */ +static int __init dwc_otg_driver_init(void) +{ + int retval = 0; + int error; + printk(KERN_INFO "%s: version %s (%s bus)\n", dwc_driver_name, + DWC_DRIVER_VERSION, +#ifdef LM_INTERFACE + "logicmodule"); + retval = lm_driver_register(&dwc_otg_driver); +#elif defined(PCI_INTERFACE) + "pci"); + retval = pci_register_driver(&dwc_otg_driver); +#elif defined(PLATFORM_INTERFACE) + "platform"); + retval = platform_driver_register(&dwc_otg_driver); +#endif + if (retval < 0) { + printk(KERN_ERR "%s retval=%d\n", __func__, retval); + return retval; + } +#ifdef LM_INTERFACE + error = driver_create_file(&dwc_otg_driver.drv, &driver_attr_version); + error = driver_create_file(&dwc_otg_driver.drv, &driver_attr_debuglevel); +#elif defined(PCI_INTERFACE) + error = driver_create_file(&dwc_otg_driver.driver, + &driver_attr_version); + error = driver_create_file(&dwc_otg_driver.driver, + &driver_attr_debuglevel); +#elif defined(PLATFORM_INTERFACE) + error = driver_create_file(&dwc_otg_driver.driver, + &driver_attr_version); + error = driver_create_file(&dwc_otg_driver.driver, + &driver_attr_debuglevel); +#endif + return retval; +} + +module_init(dwc_otg_driver_init); + +/** + * This function is called when the driver is removed from the kernel + * with the rmmod command. The driver unregisters itself with its bus + * driver. + * + */ +static void __exit dwc_otg_driver_cleanup(void) +{ + printk(KERN_DEBUG "dwc_otg_driver_cleanup()\n"); + +#ifdef LM_INTERFACE + driver_remove_file(&dwc_otg_driver.drv, &driver_attr_debuglevel); + driver_remove_file(&dwc_otg_driver.drv, &driver_attr_version); + lm_driver_unregister(&dwc_otg_driver); +#elif defined(PCI_INTERFACE) + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel); + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version); + pci_unregister_driver(&dwc_otg_driver); +#elif defined(PLATFORM_INTERFACE) + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel); + driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version); + platform_driver_unregister(&dwc_otg_driver); +#endif + + printk(KERN_INFO "%s module removed\n", dwc_driver_name); +} +module_exit(dwc_otg_driver_cleanup); + +MODULE_DESCRIPTION(DWC_DRIVER_DESC); +MODULE_AUTHOR("Synopsys Inc."); +MODULE_LICENSE("GPL"); + +module_param_named(otg_cap, dwc_otg_module_params.otg_cap, int, 0444); +MODULE_PARM_DESC(otg_cap, "OTG Capabilities 0=HNP&SRP 1=SRP Only 2=None"); +module_param_named(opt, dwc_otg_module_params.opt, int, 0444); +MODULE_PARM_DESC(opt, "OPT Mode"); +module_param_named(dma_enable, dwc_otg_module_params.dma_enable, int, 0444); +MODULE_PARM_DESC(dma_enable, "DMA Mode 0=Slave 1=DMA enabled"); + +module_param_named(dma_desc_enable, dwc_otg_module_params.dma_desc_enable, int, + 0444); +MODULE_PARM_DESC(dma_desc_enable, + "DMA Desc Mode 0=Address DMA 1=DMA Descriptor enabled"); + +module_param_named(dma_burst_size, dwc_otg_module_params.dma_burst_size, int, + 0444); +MODULE_PARM_DESC(dma_burst_size, + "DMA Burst Size 1, 4, 8, 16, 32, 64, 128, 256"); +module_param_named(speed, dwc_otg_module_params.speed, int, 0444); +MODULE_PARM_DESC(speed, "Speed 0=High Speed 1=Full Speed"); +module_param_named(host_support_fs_ls_low_power, + dwc_otg_module_params.host_support_fs_ls_low_power, int, + 0444); +MODULE_PARM_DESC(host_support_fs_ls_low_power, + "Support Low Power w/FS or LS 0=Support 1=Don't Support"); +module_param_named(host_ls_low_power_phy_clk, + dwc_otg_module_params.host_ls_low_power_phy_clk, int, 0444); +MODULE_PARM_DESC(host_ls_low_power_phy_clk, + "Low Speed Low Power Clock 0=48Mhz 1=6Mhz"); +module_param_named(enable_dynamic_fifo, + dwc_otg_module_params.enable_dynamic_fifo, int, 0444); +MODULE_PARM_DESC(enable_dynamic_fifo, "0=cC Setting 1=Allow Dynamic Sizing"); +module_param_named(data_fifo_size, dwc_otg_module_params.data_fifo_size, int, + 0444); +MODULE_PARM_DESC(data_fifo_size, + "Total number of words in the data FIFO memory 32-32768"); +module_param_named(dev_rx_fifo_size, dwc_otg_module_params.dev_rx_fifo_size, + int, 0444); +MODULE_PARM_DESC(dev_rx_fifo_size, "Number of words in the Rx FIFO 16-32768"); +module_param_named(dev_nperio_tx_fifo_size, + dwc_otg_module_params.dev_nperio_tx_fifo_size, int, 0444); +MODULE_PARM_DESC(dev_nperio_tx_fifo_size, + "Number of words in the non-periodic Tx FIFO 16-32768"); +module_param_named(dev_perio_tx_fifo_size_1, + dwc_otg_module_params.dev_perio_tx_fifo_size[0], int, 0444); +MODULE_PARM_DESC(dev_perio_tx_fifo_size_1, + "Number of words in the periodic Tx FIFO 4-768"); +module_param_named(dev_perio_tx_fifo_size_2, + dwc_otg_module_params.dev_perio_tx_fifo_size[1], int, 0444); +MODULE_PARM_DESC(dev_perio_tx_fifo_size_2, + "Number of words in the periodic Tx FIFO 4-768"); +module_param_named(dev_perio_tx_fifo_size_3, + dwc_otg_module_params.dev_perio_tx_fifo_size[2], int, 0444); +MODULE_PARM_DESC(dev_perio_tx_fifo_size_3, + "Number of words in the periodic Tx FIFO 4-768"); +module_param_named(dev_perio_tx_fifo_size_4, + dwc_otg_module_params.dev_perio_tx_fifo_size[3], int, 0444); +MODULE_PARM_DESC(dev_perio_tx_fifo_size_4, + "Number of words in the periodic Tx FIFO 4-768"); +module_param_named(dev_perio_tx_fifo_size_5, + dwc_otg_module_params.dev_perio_tx_fifo_size[4], int, 0444); +MODULE_PARM_DESC(dev_perio_tx_fifo_size_5, + "Number of words in the periodic Tx FIFO 4-768"); +module_param_named(dev_perio_tx_fifo_size_6, + dwc_otg_module_params.dev_perio_tx_fifo_size[5], int, 0444); +MODULE_PARM_DESC(dev_perio_tx_fifo_size_6, + "Number of words in the periodic Tx FIFO 4-768"); +module_param_named(dev_perio_tx_fifo_size_7, + dwc_otg_module_params.dev_perio_tx_fifo_size[6], int, 0444); +MODULE_PARM_DESC(dev_perio_tx_fifo_size_7, + "Number of words in the periodic Tx FIFO 4-768"); +module_param_named(dev_perio_tx_fifo_size_8, + dwc_otg_module_params.dev_perio_tx_fifo_size[7], int, 0444); +MODULE_PARM_DESC(dev_perio_tx_fifo_size_8, + "Number of words in the periodic Tx FIFO 4-768"); +module_param_named(dev_perio_tx_fifo_size_9, + dwc_otg_module_params.dev_perio_tx_fifo_size[8], int, 0444); +MODULE_PARM_DESC(dev_perio_tx_fifo_size_9, + "Number of words in the periodic Tx FIFO 4-768"); +module_param_named(dev_perio_tx_fifo_size_10, + dwc_otg_module_params.dev_perio_tx_fifo_size[9], int, 0444); +MODULE_PARM_DESC(dev_perio_tx_fifo_size_10, + "Number of words in the periodic Tx FIFO 4-768"); +module_param_named(dev_perio_tx_fifo_size_11, + dwc_otg_module_params.dev_perio_tx_fifo_size[10], int, 0444); +MODULE_PARM_DESC(dev_perio_tx_fifo_size_11, + "Number of words in the periodic Tx FIFO 4-768"); +module_param_named(dev_perio_tx_fifo_size_12, + dwc_otg_module_params.dev_perio_tx_fifo_size[11], int, 0444); +MODULE_PARM_DESC(dev_perio_tx_fifo_size_12, + "Number of words in the periodic Tx FIFO 4-768"); +module_param_named(dev_perio_tx_fifo_size_13, + dwc_otg_module_params.dev_perio_tx_fifo_size[12], int, 0444); +MODULE_PARM_DESC(dev_perio_tx_fifo_size_13, + "Number of words in the periodic Tx FIFO 4-768"); +module_param_named(dev_perio_tx_fifo_size_14, + dwc_otg_module_params.dev_perio_tx_fifo_size[13], int, 0444); +MODULE_PARM_DESC(dev_perio_tx_fifo_size_14, + "Number of words in the periodic Tx FIFO 4-768"); +module_param_named(dev_perio_tx_fifo_size_15, + dwc_otg_module_params.dev_perio_tx_fifo_size[14], int, 0444); +MODULE_PARM_DESC(dev_perio_tx_fifo_size_15, + "Number of words in the periodic Tx FIFO 4-768"); +module_param_named(host_rx_fifo_size, dwc_otg_module_params.host_rx_fifo_size, + int, 0444); +MODULE_PARM_DESC(host_rx_fifo_size, "Number of words in the Rx FIFO 16-32768"); +module_param_named(host_nperio_tx_fifo_size, + dwc_otg_module_params.host_nperio_tx_fifo_size, int, 0444); +MODULE_PARM_DESC(host_nperio_tx_fifo_size, + "Number of words in the non-periodic Tx FIFO 16-32768"); +module_param_named(host_perio_tx_fifo_size, + dwc_otg_module_params.host_perio_tx_fifo_size, int, 0444); +MODULE_PARM_DESC(host_perio_tx_fifo_size, + "Number of words in the host periodic Tx FIFO 16-32768"); +module_param_named(max_transfer_size, dwc_otg_module_params.max_transfer_size, + int, 0444); +/** @todo Set the max to 512K, modify checks */ +MODULE_PARM_DESC(max_transfer_size, + "The maximum transfer size supported in bytes 2047-65535"); +module_param_named(max_packet_count, dwc_otg_module_params.max_packet_count, + int, 0444); +MODULE_PARM_DESC(max_packet_count, + "The maximum number of packets in a transfer 15-511"); +module_param_named(host_channels, dwc_otg_module_params.host_channels, int, + 0444); +MODULE_PARM_DESC(host_channels, + "The number of host channel registers to use 1-16"); +module_param_named(dev_endpoints, dwc_otg_module_params.dev_endpoints, int, + 0444); +MODULE_PARM_DESC(dev_endpoints, + "The number of endpoints in addition to EP0 available for device mode 1-15"); +module_param_named(phy_type, dwc_otg_module_params.phy_type, int, 0444); +MODULE_PARM_DESC(phy_type, "0=Reserved 1=UTMI+ 2=ULPI"); +module_param_named(phy_utmi_width, dwc_otg_module_params.phy_utmi_width, int, + 0444); +MODULE_PARM_DESC(phy_utmi_width, "Specifies the UTMI+ Data Width 8 or 16 bits"); +module_param_named(phy_ulpi_ddr, dwc_otg_module_params.phy_ulpi_ddr, int, 0444); +MODULE_PARM_DESC(phy_ulpi_ddr, + "ULPI at double or single data rate 0=Single 1=Double"); +module_param_named(phy_ulpi_ext_vbus, dwc_otg_module_params.phy_ulpi_ext_vbus, + int, 0444); +MODULE_PARM_DESC(phy_ulpi_ext_vbus, + "ULPI PHY using internal or external vbus 0=Internal"); +module_param_named(i2c_enable, dwc_otg_module_params.i2c_enable, int, 0444); +MODULE_PARM_DESC(i2c_enable, "FS PHY Interface"); +module_param_named(ulpi_fs_ls, dwc_otg_module_params.ulpi_fs_ls, int, 0444); +MODULE_PARM_DESC(ulpi_fs_ls, "ULPI PHY FS/LS mode only"); +module_param_named(ts_dline, dwc_otg_module_params.ts_dline, int, 0444); +MODULE_PARM_DESC(ts_dline, "Term select Dline pulsing for all PHYs"); +module_param_named(debug, g_dbg_lvl, int, 0444); +MODULE_PARM_DESC(debug, ""); + +module_param_named(en_multiple_tx_fifo, + dwc_otg_module_params.en_multiple_tx_fifo, int, 0444); +MODULE_PARM_DESC(en_multiple_tx_fifo, + "Dedicated Non Periodic Tx FIFOs 0=disabled 1=enabled"); +module_param_named(dev_tx_fifo_size_1, + dwc_otg_module_params.dev_tx_fifo_size[0], int, 0444); +MODULE_PARM_DESC(dev_tx_fifo_size_1, "Number of words in the Tx FIFO 4-768"); +module_param_named(dev_tx_fifo_size_2, + dwc_otg_module_params.dev_tx_fifo_size[1], int, 0444); +MODULE_PARM_DESC(dev_tx_fifo_size_2, "Number of words in the Tx FIFO 4-768"); +module_param_named(dev_tx_fifo_size_3, + dwc_otg_module_params.dev_tx_fifo_size[2], int, 0444); +MODULE_PARM_DESC(dev_tx_fifo_size_3, "Number of words in the Tx FIFO 4-768"); +module_param_named(dev_tx_fifo_size_4, + dwc_otg_module_params.dev_tx_fifo_size[3], int, 0444); +MODULE_PARM_DESC(dev_tx_fifo_size_4, "Number of words in the Tx FIFO 4-768"); +module_param_named(dev_tx_fifo_size_5, + dwc_otg_module_params.dev_tx_fifo_size[4], int, 0444); +MODULE_PARM_DESC(dev_tx_fifo_size_5, "Number of words in the Tx FIFO 4-768"); +module_param_named(dev_tx_fifo_size_6, + dwc_otg_module_params.dev_tx_fifo_size[5], int, 0444); +MODULE_PARM_DESC(dev_tx_fifo_size_6, "Number of words in the Tx FIFO 4-768"); +module_param_named(dev_tx_fifo_size_7, + dwc_otg_module_params.dev_tx_fifo_size[6], int, 0444); +MODULE_PARM_DESC(dev_tx_fifo_size_7, "Number of words in the Tx FIFO 4-768"); +module_param_named(dev_tx_fifo_size_8, + dwc_otg_module_params.dev_tx_fifo_size[7], int, 0444); +MODULE_PARM_DESC(dev_tx_fifo_size_8, "Number of words in the Tx FIFO 4-768"); +module_param_named(dev_tx_fifo_size_9, + dwc_otg_module_params.dev_tx_fifo_size[8], int, 0444); +MODULE_PARM_DESC(dev_tx_fifo_size_9, "Number of words in the Tx FIFO 4-768"); +module_param_named(dev_tx_fifo_size_10, + dwc_otg_module_params.dev_tx_fifo_size[9], int, 0444); +MODULE_PARM_DESC(dev_tx_fifo_size_10, "Number of words in the Tx FIFO 4-768"); +module_param_named(dev_tx_fifo_size_11, + dwc_otg_module_params.dev_tx_fifo_size[10], int, 0444); +MODULE_PARM_DESC(dev_tx_fifo_size_11, "Number of words in the Tx FIFO 4-768"); +module_param_named(dev_tx_fifo_size_12, + dwc_otg_module_params.dev_tx_fifo_size[11], int, 0444); +MODULE_PARM_DESC(dev_tx_fifo_size_12, "Number of words in the Tx FIFO 4-768"); +module_param_named(dev_tx_fifo_size_13, + dwc_otg_module_params.dev_tx_fifo_size[12], int, 0444); +MODULE_PARM_DESC(dev_tx_fifo_size_13, "Number of words in the Tx FIFO 4-768"); +module_param_named(dev_tx_fifo_size_14, + dwc_otg_module_params.dev_tx_fifo_size[13], int, 0444); +MODULE_PARM_DESC(dev_tx_fifo_size_14, "Number of words in the Tx FIFO 4-768"); +module_param_named(dev_tx_fifo_size_15, + dwc_otg_module_params.dev_tx_fifo_size[14], int, 0444); +MODULE_PARM_DESC(dev_tx_fifo_size_15, "Number of words in the Tx FIFO 4-768"); + +module_param_named(thr_ctl, dwc_otg_module_params.thr_ctl, int, 0444); +MODULE_PARM_DESC(thr_ctl, + "Thresholding enable flag bit 0 - non ISO Tx thr., 1 - ISO Tx thr., 2 - Rx thr.- bit 0=disabled 1=enabled"); +module_param_named(tx_thr_length, dwc_otg_module_params.tx_thr_length, int, + 0444); +MODULE_PARM_DESC(tx_thr_length, "Tx Threshold length in 32 bit DWORDs"); +module_param_named(rx_thr_length, dwc_otg_module_params.rx_thr_length, int, + 0444); +MODULE_PARM_DESC(rx_thr_length, "Rx Threshold length in 32 bit DWORDs"); + +module_param_named(pti_enable, dwc_otg_module_params.pti_enable, int, 0444); +module_param_named(mpi_enable, dwc_otg_module_params.mpi_enable, int, 0444); +module_param_named(lpm_enable, dwc_otg_module_params.lpm_enable, int, 0444); +MODULE_PARM_DESC(lpm_enable, "LPM Enable 0=LPM Disabled 1=LPM Enabled"); +module_param_named(ic_usb_cap, dwc_otg_module_params.ic_usb_cap, int, 0444); +MODULE_PARM_DESC(ic_usb_cap, + "IC_USB Capability 0=IC_USB Disabled 1=IC_USB Enabled"); +module_param_named(ahb_thr_ratio, dwc_otg_module_params.ahb_thr_ratio, int, 0444); +MODULE_PARM_DESC(ahb_thr_ratio, "AHB Threshold Ratio"); + +/** @page "Module Parameters" + * + * The following parameters may be specified when starting the module. + * These parameters define how the DWC_otg controller should be + * configured. Parameter values are passed to the CIL initialization + * function dwc_otg_cil_init + * + * Example: modprobe dwc_otg speed=1 otg_cap=1 + * + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +*/ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.h b/drivers/usb/host/dwc_otg/dwc_otg_driver.h new file mode 100644 index 000000000000..f37d3ac15d00 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.h @@ -0,0 +1,101 @@ +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.h $ + * $Revision: #16 $ + * $Date: 2009/04/03 $ + * $Change: 1225160 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +#ifndef __DWC_OTG_DRIVER_H__ +#define __DWC_OTG_DRIVER_H__ + +/** @file + * This file contains the interface to the Linux driver. + */ +#include "dwc_otg_core_if.h" + +/* Type declarations */ +struct dwc_otg_pcd; +struct dwc_otg_hcd; + +#ifdef PCI_INTERFACE +#include +#endif + + + +/** + * This structure is a wrapper that encapsulates the driver components used to + * manage a single DWC_otg controller. + */ +typedef struct dwc_otg_device { + /** Base address returned from ioremap() */ + void *base; + +#ifdef LM_INTERFACE + struct lm_device *lmdev; +#elif defined(PCI_INTERFACE) + int rsrc_start; + int rsrc_len; +#elif defined(PLATFORM_INTERFACE) + struct platform_device *platformdev; +#endif + + /** Pointer to the core interface structure. */ + dwc_otg_core_if_t *core_if; + + /** Register offset for Diagnostic API. */ + uint32_t reg_offset; + + /** Pointer to the PCD structure. */ + struct dwc_otg_pcd *pcd; + + /** Pointer to the HCD structure. */ + struct dwc_otg_hcd *hcd; + + /** Flag to indicate whether the common IRQ handler is installed. */ + uint8_t common_irq_installed; + +} dwc_otg_device_t; + +/*We must clear S3C24XX_EINTPEND external interrupt register + * because after clearing in this register trigerred IRQ from + * H/W core in kernel interrupt can be occured again before OTG + * handlers clear all IRQ sources of Core registers because of + * timing latencies and Low Level IRQ Type. + */ +#ifdef CONFIG_MACH_IPMATE +#define S3C2410X_CLEAR_EINTPEND() \ +do { \ + __raw_writel(1UL << 11,S3C24XX_EINTPEND); \ +} while (0) +#else +#define S3C2410X_CLEAR_EINTPEND() do { } while (0) +#endif + +#endif diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c new file mode 100644 index 000000000000..223d879cbd5c --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c @@ -0,0 +1,3330 @@ + +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.c $ + * $Revision: #87 $ + * $Date: 2009/04/23 $ + * $Change: 1239143 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ +#ifndef DWC_DEVICE_ONLY + +/** @file + * This file implements HCD Core. All code in this file is portable and don't + * use any OS specific functions. + * Interface provided by HCD Core is defined in + * header file. + */ + +#include "dwc_otg_hcd.h" +#include "dwc_otg_regs.h" + +#ifdef HW2937_WORKAROUND +//#include +#include +#endif + +dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void) +{ + return dwc_alloc(sizeof(dwc_otg_hcd_t)); +} + +/** + * Connection timeout function. An OTG host is required to display a + * message if the device does not connect within 10 seconds. + */ +void dwc_otg_hcd_connect_timeout(void *ptr) +{ + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, ptr); + DWC_PRINTF("Connect Timeout\n"); + __DWC_ERROR("Device Not Connected/Responding\n"); +} + +#ifdef DEBUG +static void dump_channel_info(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) +{ + if (qh->channel != NULL) { + dwc_hc_t *hc = qh->channel; + dwc_list_link_t *item; + dwc_otg_qh_t *qh_item; + int num_channels = hcd->core_if->core_params->host_channels; + int i; + + dwc_otg_hc_regs_t *hc_regs; + hcchar_data_t hcchar; + hcsplt_data_t hcsplt; + hctsiz_data_t hctsiz; + uint32_t hcdma; + + hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num]; + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt); + hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz); + hcdma = dwc_read_reg32(&hc_regs->hcdma); + + DWC_PRINTF(" Assigned to channel %p:\n", hc); + DWC_PRINTF(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, + hcsplt.d32); + DWC_PRINTF(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, + hcdma); + DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n", + hc->dev_addr, hc->ep_num, hc->ep_is_in); + DWC_PRINTF(" ep_type: %d\n", hc->ep_type); + DWC_PRINTF(" max_packet: %d\n", hc->max_packet); + DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start); + DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started); + DWC_PRINTF(" halt_status: %d\n", hc->halt_status); + DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff); + DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len); + DWC_PRINTF(" qh: %p\n", hc->qh); + DWC_PRINTF(" NP inactive sched:\n"); + DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_inactive) { + qh_item = + DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry); + DWC_PRINTF(" %p\n", qh_item); + } + DWC_PRINTF(" NP active sched:\n"); + DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_active) { + qh_item = + DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry); + DWC_PRINTF(" %p\n", qh_item); + } + DWC_PRINTF(" Channels: \n"); + for (i = 0; i < num_channels; i++) { + dwc_hc_t *hc = hcd->hc_ptr_array[i]; + DWC_PRINTF(" %2d: %p\n", i, hc); + } + } +} +#endif /* DEBUG */ + +/** + * Work queue function for starting the HCD when A-Cable is connected. + * The hcd_start() must be called in a process context. + */ +static void hcd_start_func(void *_vp) +{ + dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) _vp; + + DWC_DEBUGPL(DBG_HCDV, "%s() %p\n", __func__, hcd); + if (hcd) { + hcd->fops->start(hcd); + } +} + +static void del_xfer_timers(dwc_otg_hcd_t * hcd) +{ +#ifdef DEBUG + int i; + int num_channels = hcd->core_if->core_params->host_channels; + for (i = 0; i < num_channels; i++) { + DWC_TIMER_CANCEL(hcd->core_if->hc_xfer_timer[i]); + } +#endif +} + +static void del_timers(dwc_otg_hcd_t * hcd) +{ + del_xfer_timers(hcd); + DWC_TIMER_CANCEL(hcd->conn_timer); +} + +/** + * Processes all the URBs in a single list of QHs. Completes them with + * -ETIMEDOUT and frees the QTD. + */ +static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list) +{ + dwc_list_link_t *qh_item; + dwc_otg_qh_t *qh; + dwc_otg_qtd_t *qtd, *qtd_tmp; + + DWC_LIST_FOREACH(qh_item, qh_list) { + qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry); + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, + &qh->qtd_list, qtd_list_entry) { + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); + if (qtd->urb != NULL) { + hcd->fops->complete(hcd, qtd->urb->priv, + qtd->urb, + -DWC_E_TIMEOUT); + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh); + } + + } + } +} + +/** + * Responds with an error status of ETIMEDOUT to all URBs in the non-periodic + * and periodic schedules. The QTD associated with each URB is removed from + * the schedule and freed. This function may be called when a disconnect is + * detected or when the HCD is being stopped. + */ +static void kill_all_urbs(dwc_otg_hcd_t * hcd) +{ + kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_inactive); + kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_active); + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_inactive); + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_ready); + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_assigned); + kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_queued); +} + +/** + * Start the connection timer. An OTG host is required to display a + * message if the device does not connect within 10 seconds. The + * timer is deleted if a port connect interrupt occurs before the + * timer expires. + */ +static void dwc_otg_hcd_start_connect_timer(dwc_otg_hcd_t * hcd) +{ + DWC_TIMER_SCHEDULE(hcd->conn_timer, 10000 /* 10 secs */ ); +} + +/** + * HCD Callback function for disconnect of the HCD. + * + * @param p void pointer to the struct usb_hcd + */ +static int32_t dwc_otg_hcd_session_start_cb(void *p) +{ + dwc_otg_hcd_t *dwc_otg_hcd; + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p); + dwc_otg_hcd = p; + dwc_otg_hcd_start_connect_timer(dwc_otg_hcd); + return 1; +} + +/** + * HCD Callback function for starting the HCD when A-Cable is + * connected. + * + * @param p void pointer to the struct usb_hcd + */ +static int32_t dwc_otg_hcd_start_cb(void *p) +{ + dwc_otg_hcd_t *dwc_otg_hcd = p; + dwc_otg_core_if_t *core_if; + hprt0_data_t hprt0; + + core_if = dwc_otg_hcd->core_if; + + if (core_if->op_state == B_HOST) { + /* + * Reset the port. During a HNP mode switch the reset + * needs to occur within 1ms and have a duration of at + * least 50ms. + */ + hprt0.d32 = dwc_otg_read_hprt0(core_if); + hprt0.b.prtrst = 1; + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); + } + DWC_WORKQ_SCHEDULE_DELAYED(core_if->wq_otg, + hcd_start_func, dwc_otg_hcd, 50, + "start hcd"); + + return 1; +} + +/** + * HCD Callback function for disconnect of the HCD. + * + * @param p void pointer to the struct usb_hcd + */ +static int32_t dwc_otg_hcd_disconnect_cb(void *p) +{ + gintsts_data_t intr; + dwc_otg_hcd_t *dwc_otg_hcd = p; + + /* + * Set status flags for the hub driver. + */ + dwc_otg_hcd->flags.b.port_connect_status_change = 1; + dwc_otg_hcd->flags.b.port_connect_status = 0; + + /* + * Shutdown any transfers in process by clearing the Tx FIFO Empty + * interrupt mask and status bits and disabling subsequent host + * channel interrupts. + */ + intr.d32 = 0; + intr.b.nptxfempty = 1; + intr.b.ptxfempty = 1; + intr.b.hcintr = 1; + dwc_modify_reg32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk, + intr.d32, 0); + dwc_modify_reg32(&dwc_otg_hcd->core_if->core_global_regs->gintsts, + intr.d32, 0); + + del_timers(dwc_otg_hcd); + + /* + * Turn off the vbus power only if the core has transitioned to device + * mode. If still in host mode, need to keep power on to detect a + * reconnection. + */ + if (dwc_otg_is_device_mode(dwc_otg_hcd->core_if)) { + if (dwc_otg_hcd->core_if->op_state != A_SUSPEND) { + hprt0_data_t hprt0 = {.d32 = 0 }; + DWC_PRINTF("Disconnect: PortPower off\n"); + hprt0.b.prtpwr = 0; + dwc_write_reg32(dwc_otg_hcd->core_if->host_if->hprt0, + hprt0.d32); + } + + dwc_otg_disable_host_interrupts(dwc_otg_hcd->core_if); + } + + /* Respond with an error status to all URBs in the schedule. */ + kill_all_urbs(dwc_otg_hcd); + + if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) { + /* Clean up any host channels that were in use. */ + int num_channels; + int i; + dwc_hc_t *channel; + dwc_otg_hc_regs_t *hc_regs; + hcchar_data_t hcchar; + + num_channels = dwc_otg_hcd->core_if->core_params->host_channels; + + if (!dwc_otg_hcd->core_if->dma_enable) { + /* Flush out any channel requests in slave mode. */ + for (i = 0; i < num_channels; i++) { + channel = dwc_otg_hcd->hc_ptr_array[i]; + if (DWC_CIRCLEQ_EMPTY_ENTRY + (channel, hc_list_entry)) { + hc_regs = + dwc_otg_hcd->core_if->host_if-> + hc_regs[i]; + hcchar.d32 = + dwc_read_reg32(&hc_regs->hcchar); + if (hcchar.b.chen) { + hcchar.b.chen = 0; + hcchar.b.chdis = 1; + hcchar.b.epdir = 0; + dwc_write_reg32(&hc_regs-> + hcchar, + hcchar.d32); + } + } + } + } + + for (i = 0; i < num_channels; i++) { + channel = dwc_otg_hcd->hc_ptr_array[i]; + if (DWC_CIRCLEQ_EMPTY_ENTRY(channel, hc_list_entry)) { + hc_regs = + dwc_otg_hcd->core_if->host_if->hc_regs[i]; + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + if (hcchar.b.chen) { + /* Halt the channel. */ + hcchar.b.chdis = 1; + dwc_write_reg32(&hc_regs->hcchar, + hcchar.d32); + } + + dwc_otg_hc_cleanup(dwc_otg_hcd->core_if, + channel); + DWC_CIRCLEQ_INSERT_TAIL(&dwc_otg_hcd-> + free_hc_list, channel, + hc_list_entry); + /* + * Added for Descriptor DMA to prevent channel double cleanup + * in release_channel_ddma(). Which called from ep_disable + * when device disconnect. + */ + channel->qh = NULL; + } + } + } + + if (dwc_otg_hcd->fops->disconnect) { + dwc_otg_hcd->fops->disconnect(dwc_otg_hcd); + } + + return 1; +} + +/** + * HCD Callback function for stopping the HCD. + * + * @param p void pointer to the struct usb_hcd + */ +static int32_t dwc_otg_hcd_stop_cb(void *p) +{ + dwc_otg_hcd_t *dwc_otg_hcd = p; + + DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p); + dwc_otg_hcd_stop(dwc_otg_hcd); + return 1; +} + +#ifdef CONFIG_USB_DWC_OTG_LPM +/** + * HCD Callback function for sleep of HCD. + * + * @param p void pointer to the struct usb_hcd + */ +static int dwc_otg_hcd_sleep_cb(void *p) +{ + dwc_otg_hcd_t *hcd = p; + + dwc_otg_hcd_free_hc_from_lpm(hcd); + + return 0; +} +#endif + +/** + * HCD Callback function for Remote Wakeup. + * + * @param p void pointer to the struct usb_hcd + */ +static int dwc_otg_hcd_rem_wakeup_cb(void *p) +{ + dwc_otg_hcd_t *hcd = p; + + if (hcd->core_if->lx_state == DWC_OTG_L2) { + hcd->flags.b.port_suspend_change = 1; + } +#ifdef CONFIG_USB_DWC_OTG_LPM + else { + hcd->flags.b.port_l1_change = 1; + } +#endif + return 0; +} + +/** + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are + * stopped. + */ +void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd) +{ + hprt0_data_t hprt0 = {.d32 = 0 }; + + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n"); + + /* + * The root hub should be disconnected before this function is called. + * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue) + * and the QH lists (via ..._hcd_endpoint_disable). + */ + + /* Turn off all host-specific interrupts. */ + dwc_otg_disable_host_interrupts(hcd->core_if); + + /* Turn off the vbus power */ + DWC_PRINTF("PortPower off\n"); + hprt0.b.prtpwr = 0; + dwc_write_reg32(hcd->core_if->host_if->hprt0, hprt0.d32); + dwc_mdelay(1); +} + +int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd, + dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle) +{ + uint64_t flags; + int retval = 0; + dwc_otg_qtd_t *qtd; + + if (NULL == hcd->core_if) { //GRAYG + DWC_ERROR("**** DWC OTG HCD URB Enqueue - HCD has NULL core_if\n"); + /* No longer connected. */ + return -DWC_E_INVALID; + } + + if (!hcd->flags.b.port_connect_status) { + /* No longer connected. */ + return -DWC_E_NO_DEVICE; + } + + qtd = dwc_otg_hcd_qtd_create(dwc_otg_urb); + if (qtd == NULL) { + DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n"); + return -DWC_E_NO_MEMORY; + } + if (qtd->urb == NULL) { //GRAYG + DWC_ERROR("**** DWC OTG HCD URB Enqueue created QTD with no URBs\n"); + return -DWC_E_NO_MEMORY; + } + if (qtd->urb->priv == NULL) { //GRAYG + DWC_ERROR("**** DWC OTG HCD URB Enqueue created QTD URB with no URB handle\n"); + return -DWC_E_NO_MEMORY; + } + + retval = + dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle); + // creates a new queue in ep_handle if it doesn't exist already + if (retval < 0) { + DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. " + "Error status %d\n", retval); + dwc_otg_hcd_qtd_free(qtd); + } else { + qtd->qh = *ep_handle; + } + + if (hcd->core_if->dma_desc_enable && retval == 0) { + dwc_otg_transaction_type_e tr_type; + if ((qtd->qh->ep_type == UE_BULK) && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) { + /* Do not schedule SG transcations until qtd has URB_GIVEBACK_ASAP set */ + return 0; + } + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); + tr_type = dwc_otg_hcd_select_transactions(hcd); + if (tr_type != DWC_OTG_TRANSACTION_NONE) { + dwc_otg_hcd_queue_transactions(hcd, tr_type); + } + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); + } + + return retval; +} + +int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd, + dwc_otg_hcd_urb_t * dwc_otg_urb) +{ + uint64_t flags; + + dwc_otg_qh_t *qh; + dwc_otg_qtd_t *urb_qtd; + + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); + + if (hcd == NULL) { //GRAYG + DWC_ERROR("**** DWC OTG HCD URB Dequeue has NULL HCD\n"); + return -DWC_E_INVALID; + } + if (dwc_otg_urb == NULL) { //GRAYG + DWC_ERROR("**** DWC OTG HCD URB Dequeue has NULL URB\n"); + return -DWC_E_INVALID; + } + if (dwc_otg_urb->qtd == NULL) { //GRAYG + DWC_ERROR("**** DWC OTG HCD URB Dequeue with NULL QTD\n"); + return -DWC_E_INVALID; + } + urb_qtd = dwc_otg_urb->qtd; + if (urb_qtd->qh == NULL) { //GRAYG + DWC_ERROR("**** DWC OTG HCD URB Dequeue with QTD with NULL Q handler\n"); + return -DWC_E_INVALID; + } + qh = urb_qtd->qh; +#ifdef DEBUG + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { + if (urb_qtd->in_process) { + dump_channel_info(hcd, qh); + } + } +#endif + if (hcd->core_if == NULL) { //GRAYG + DWC_ERROR("**** DWC OTG HCD URB Dequeue HCD has NULL core_if\n"); + return -DWC_E_INVALID; + } + if (urb_qtd->in_process && qh->channel) { + /* The QTD is in process (it has been assigned to a channel). */ + if (hcd->flags.b.port_connect_status) { + /* + * If still connected (i.e. in host mode), halt the + * channel so it can be used for other transfers. If + * no longer connected, the host registers can't be + * written to halt the channel since the core is in + * device mode. + */ + dwc_otg_hc_halt(hcd->core_if, qh->channel, + DWC_OTG_HC_XFER_URB_DEQUEUE); + } + } + + /* + * Free the QTD and clean up the associated QH. Leave the QH in the + * schedule if it has any remaining QTDs. + */ + + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue - " + "delete %sQueue handler\n", + hcd->core_if->dma_desc_enable?"DMA ":""); //GRAYG + if (!hcd->core_if->dma_desc_enable) { + uint8_t b = urb_qtd->in_process; + dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh); + if (b) { + dwc_otg_hcd_qh_deactivate(hcd, qh, 0); + qh->channel = NULL; + } else if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) { + dwc_otg_hcd_qh_remove(hcd, qh); + } + } + else { + dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh); + } + + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); + + return 0; +} + +int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle, + int retry) +{ + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle; + int retval = 0; + uint64_t flags; + + if (retry < 0) { + retval = -DWC_E_INVALID; + goto done; + } + + if (!qh) { + goto done; + } + + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); + + while (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list) && retry) { + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); + retry--; + dwc_msleep(5); + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); + } + + dwc_otg_hcd_qh_remove(hcd, qh); + + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); + /* + * Split dwc_otg_hcd_qh_remove_and_free() into qh_remove + * and qh_free to prevent stack dump on dwc_dma_free() with + * irq_disabled (spinlock_irqsave) in dwc_otg_hcd_desc_list_free() + * and dwc_otg_hcd_frame_list_alloc(). + */ + dwc_otg_hcd_qh_free(hcd, qh); + + done: + return retval; +} + +/** + * HCD Callback structure for handling mode switching. + */ +static dwc_otg_cil_callbacks_t hcd_cil_callbacks = { + .start = dwc_otg_hcd_start_cb, + .stop = dwc_otg_hcd_stop_cb, + .disconnect = dwc_otg_hcd_disconnect_cb, + .session_start = dwc_otg_hcd_session_start_cb, + .resume_wakeup = dwc_otg_hcd_rem_wakeup_cb, +#ifdef CONFIG_USB_DWC_OTG_LPM + .sleep = dwc_otg_hcd_sleep_cb, +#endif + .p = 0, +}; + +/** + * Reset tasklet function + */ +static void reset_tasklet_func(void *data) +{ + dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t *) data; + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if; + hprt0_data_t hprt0; + + DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n"); + + hprt0.d32 = dwc_otg_read_hprt0(core_if); + hprt0.b.prtrst = 1; + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); + dwc_mdelay(60); + + hprt0.b.prtrst = 0; + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); + dwc_otg_hcd->flags.b.port_reset_change = 1; +} + +static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list) +{ + dwc_list_link_t *item; + dwc_otg_qh_t *qh; + + if (!qh_list->next) { + /* The list hasn't been initialized yet. */ + return; + } + + /* Ensure there are no QTDs or URBs left. */ + kill_urbs_in_qh_list(hcd, qh_list); + + DWC_LIST_FOREACH(item, qh_list) { + qh = DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry); + dwc_otg_hcd_qh_remove_and_free(hcd, qh); + } +} + +/** + * Frees secondary storage associated with the dwc_otg_hcd structure contained + * in the struct usb_hcd field. + */ +static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd) +{ + int i; + + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n"); + + del_timers(dwc_otg_hcd); + + /* Free memory for QH/QTD lists */ + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive); + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active); + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive); + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready); + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned); + qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued); + + /* Free memory for the host channels. */ + for (i = 0; i < MAX_EPS_CHANNELS; i++) { + dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i]; + +#ifdef DEBUG + if (dwc_otg_hcd->core_if->hc_xfer_timer[i]) { + DWC_TIMER_FREE(dwc_otg_hcd->core_if->hc_xfer_timer[i]); + } +#endif + if (hc != NULL) { + DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n", + i, hc); + dwc_free(hc); + } + } + + if (dwc_otg_hcd->core_if->dma_enable) { + if (dwc_otg_hcd->status_buf_dma) { + dwc_dma_free(DWC_OTG_HCD_STATUS_BUF_SIZE, + dwc_otg_hcd->status_buf, + dwc_otg_hcd->status_buf_dma); + } + } else if (dwc_otg_hcd->status_buf != NULL) { + dwc_free(dwc_otg_hcd->status_buf); + } + DWC_SPINLOCK_FREE(dwc_otg_hcd->lock); + DWC_TIMER_FREE(dwc_otg_hcd->conn_timer); + DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet); + dwc_free(dwc_otg_hcd); +} + +int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if) +{ + int retval = 0; + int num_channels; + int i; + dwc_hc_t *channel; + + hcd->lock = DWC_SPINLOCK_ALLOC(); + + DWC_DEBUGPL(DBG_HCDV, "init of HCD %p given core_if %p\n", + hcd, core_if);//GRAYG + + hcd->core_if = core_if; + /* Register the HCD CIL Callbacks */ + dwc_otg_cil_register_hcd_callbacks(hcd->core_if, + &hcd_cil_callbacks, hcd); + + /* Initialize the non-periodic schedule. */ + DWC_LIST_INIT(&hcd->non_periodic_sched_inactive); + DWC_LIST_INIT(&hcd->non_periodic_sched_active); + + /* Initialize the periodic schedule. */ + DWC_LIST_INIT(&hcd->periodic_sched_inactive); + DWC_LIST_INIT(&hcd->periodic_sched_ready); + DWC_LIST_INIT(&hcd->periodic_sched_assigned); + DWC_LIST_INIT(&hcd->periodic_sched_queued); + + /* + * Create a host channel descriptor for each host channel implemented + * in the controller. Initialize the channel descriptor array. + */ + DWC_CIRCLEQ_INIT(&hcd->free_hc_list); + num_channels = hcd->core_if->core_params->host_channels; + DWC_MEMSET(hcd->hc_ptr_array, 0, sizeof(hcd->hc_ptr_array)); + for (i = 0; i < num_channels; i++) { + channel = dwc_alloc(sizeof(dwc_hc_t)); + if (channel == NULL) { + retval = -DWC_E_NO_MEMORY; + DWC_ERROR("%s: host channel allocation failed\n", + __func__); + dwc_otg_hcd_free(hcd); + goto out; + } + channel->hc_num = i; + hcd->hc_ptr_array[i] = channel; +#ifdef DEBUG + hcd->core_if->hc_xfer_timer[i] = + DWC_TIMER_ALLOC("hc timer", hc_xfer_timeout, + &hcd->core_if->hc_xfer_info[i]); +#endif + DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i, + channel); + } + + /* Initialize the Connection timeout timer. */ + hcd->conn_timer = DWC_TIMER_ALLOC("Connection timer", + dwc_otg_hcd_connect_timeout, 0); + + /* Initialize reset tasklet. */ + hcd->reset_tasklet = DWC_TASK_ALLOC(reset_tasklet_func, hcd); + + /* + * Allocate space for storing data on status transactions. Normally no + * data is sent, but this space acts as a bit bucket. This must be + * done after usb_add_hcd since that function allocates the DMA buffer + * pool. + */ + if (hcd->core_if->dma_enable) { + hcd->status_buf = + dwc_dma_alloc(DWC_OTG_HCD_STATUS_BUF_SIZE, + &hcd->status_buf_dma); + } else { + hcd->status_buf = dwc_alloc(DWC_OTG_HCD_STATUS_BUF_SIZE); + } + if (!hcd->status_buf) { + retval = -DWC_E_NO_MEMORY; + DWC_ERROR("%s: status_buf allocation failed\n", __func__); + dwc_otg_hcd_free(hcd); + goto out; + } + + hcd->otg_port = 1; + hcd->frame_list = NULL; + hcd->frame_list_dma = 0; + +#ifdef HW2937_WORKAROUND + hcd->hw2937_xfer_mode = HW2937_XFER_MODE_IDLE; + hcd->hw2937_assigned_channels = 0; +#endif + +out: + return retval; +} + +void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd) +{ + /* Turn off all host-specific interrupts. */ + dwc_otg_disable_host_interrupts(hcd->core_if); + + dwc_otg_hcd_free(hcd); +} + +/** + * Initializes dynamic portions of the DWC_otg HCD state. + */ +static void dwc_otg_hcd_reinit(dwc_otg_hcd_t * hcd) +{ + int num_channels; + int i; + dwc_hc_t *channel; + dwc_hc_t *channel_tmp; + + hcd->flags.d32 = 0; + + hcd->non_periodic_qh_ptr = &hcd->non_periodic_sched_active; + hcd->non_periodic_channels = 0; + hcd->periodic_channels = 0; + + /* + * Put all channels in the free channel list and clean up channel + * states. + */ + DWC_CIRCLEQ_FOREACH_SAFE(channel, channel_tmp, + &hcd->free_hc_list, hc_list_entry) { + DWC_CIRCLEQ_REMOVE(&hcd->free_hc_list, channel, hc_list_entry); + } + + num_channels = hcd->core_if->core_params->host_channels; + for (i = 0; i < num_channels; i++) { + channel = hcd->hc_ptr_array[i]; + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, channel, + hc_list_entry); + dwc_otg_hc_cleanup(hcd->core_if, channel); + } + + /* Initialize the DWC core for host mode operation. */ + dwc_otg_core_host_init(hcd->core_if); +} + +/** + * Assigns transactions from a QTD to a free host channel and initializes the + * host channel to perform the transactions. The host channel is removed from + * the free list. + * + * @param hcd The HCD state structure. + * @param qh Transactions from the first QTD for this QH are selected and + * assigned to a free host channel. + */ +#ifdef HW2937_WORKAROUND +static int assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) +#else +static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) +#endif +{ + dwc_hc_t *hc; + dwc_otg_qtd_t *qtd; + dwc_otg_hcd_urb_t *urb; + void* ptr = NULL; +#ifdef HW2937_WORKAROUND + int ep_is_in; +#endif + + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); + + urb = qtd->urb; + + DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p) - urb %x, actual_length %d\n", __func__, hcd, qh, (unsigned int)urb, urb->actual_length); + +#ifdef HW2937_WORKAROUND + ep_is_in = (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) != 0); + if (ep_is_in && ((hcd->hw2937_xfer_mode == HW2937_XFER_MODE_OUT) || + (hcd->hw2937_xfer_mode == HW2937_XFER_MODE_PAUSEIN))) + return 0; +#endif + + hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list); + + /* Remove the host channel from the free list. */ + DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry); + qh->channel = hc; + + qtd->in_process = 1; + + /* + * Use usb_pipedevice to determine device address. This address is + * 0 before the SET_ADDRESS command and the correct address afterward. + */ + hc->dev_addr = dwc_otg_hcd_get_dev_addr(&urb->pipe_info); + hc->ep_num = dwc_otg_hcd_get_ep_num(&urb->pipe_info); + hc->speed = qh->dev_speed; + hc->max_packet = dwc_max_packet(qh->maxp); + + hc->xfer_started = 0; + hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS; + hc->error_state = (qtd->error_count > 0); + hc->halt_on_queue = 0; + hc->halt_pending = 0; + hc->requests = 0; + + /* + * The following values may be modified in the transfer type section + * below. The xfer_len value may be reduced when the transfer is + * started to accommodate the max widths of the XferSize and PktCnt + * fields in the HCTSIZn register. + */ + hc->do_ping = qh->ping_state; +#ifdef HW2937_WORKAROUND + hc->ep_is_in = ep_is_in; +#else + hc->ep_is_in = (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) != 0); +#endif + hc->data_pid_start = qh->data_toggle; + hc->multi_count = 1; + + if (hcd->core_if->dma_enable) { + hc->xfer_buff = (uint8_t *) urb->dma + urb->actual_length; + + /* For non-dword aligned case */ + if (((uint32_t)hc->xfer_buff & 0x3) && !hcd->core_if->dma_desc_enable) { + ptr = (uint8_t *) urb->buf + urb->actual_length; + } + } else { + hc->xfer_buff = (uint8_t *) urb->buf + urb->actual_length; + } + hc->xfer_len = urb->length - urb->actual_length; + hc->xfer_count = 0; + + /* + * Set the split attributes + */ + hc->do_split = 0; + if (qh->do_split) { + uint32_t hub_addr, port_addr; + hc->do_split = 1; + hc->xact_pos = qtd->isoc_split_pos; + hc->complete_split = qtd->complete_split; + hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &port_addr); + hc->hub_addr = (uint8_t) hub_addr; + hc->port_addr = (uint8_t) port_addr; + } + + switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) { + case UE_CONTROL: + hc->ep_type = DWC_OTG_EP_TYPE_CONTROL; + switch (qtd->control_phase) { + case DWC_OTG_CONTROL_SETUP: + DWC_DEBUGPL(DBG_HCDV, " Control setup transaction\n"); + hc->do_ping = 0; + hc->ep_is_in = 0; + hc->data_pid_start = DWC_OTG_HC_PID_SETUP; + if (hcd->core_if->dma_enable) { + hc->xfer_buff = (uint8_t *) urb->setup_dma; + } else { + hc->xfer_buff = (uint8_t *) urb->setup_packet; + } + hc->xfer_len = 8; + ptr = NULL; + break; + case DWC_OTG_CONTROL_DATA: + DWC_DEBUGPL(DBG_HCDV, " Control data transaction\n"); + hc->data_pid_start = qtd->data_toggle; + break; + case DWC_OTG_CONTROL_STATUS: + /* + * Direction is opposite of data direction or IN if no + * data. + */ + DWC_DEBUGPL(DBG_HCDV, " Control status transaction\n"); + if (urb->length == 0) { + hc->ep_is_in = 1; + } else { + hc->ep_is_in = + dwc_otg_hcd_is_pipe_out(&urb->pipe_info); + } + if (hc->ep_is_in) { + hc->do_ping = 0; + } + + hc->data_pid_start = DWC_OTG_HC_PID_DATA1; + + hc->xfer_len = 0; + if (hcd->core_if->dma_enable) { + hc->xfer_buff = (uint8_t *) hcd->status_buf_dma; + } else { + hc->xfer_buff = (uint8_t *) hcd->status_buf; + } + ptr = NULL; + break; + } + break; + case UE_BULK: + hc->ep_type = DWC_OTG_EP_TYPE_BULK; + break; + case UE_INTERRUPT: + hc->ep_type = DWC_OTG_EP_TYPE_INTR; + break; + case UE_ISOCHRONOUS: + { + struct dwc_otg_hcd_iso_packet_desc *frame_desc; + + hc->ep_type = DWC_OTG_EP_TYPE_ISOC; + + if (hcd->core_if->dma_desc_enable) + break; + + frame_desc = &urb->iso_descs[qtd->isoc_frame_index]; + + frame_desc->status = 0; + + if (hcd->core_if->dma_enable) { + hc->xfer_buff = (uint8_t *) urb->dma; + } else { + hc->xfer_buff = (uint8_t *) urb->buf; + } + hc->xfer_buff += + frame_desc->offset + qtd->isoc_split_offset; + hc->xfer_len = + frame_desc->length - qtd->isoc_split_offset; + + /* For non-dword aligned buffers */ + if (((uint32_t)hc->xfer_buff & 0x3) && hcd->core_if->dma_enable) { + ptr = (uint8_t *) urb->buf + frame_desc->offset + qtd->isoc_split_offset; + } + else + ptr = NULL; + + if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) { + if (hc->xfer_len <= 188) { + hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL; + } else { + hc->xact_pos = + DWC_HCSPLIT_XACTPOS_BEGIN; + } + } + } + break; + } + /* non DWORD-aligned buffer case */ + if (ptr) { + uint32_t buf_size; + if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) { + buf_size = hcd->core_if->core_params->max_transfer_size; + } else { + buf_size = 4096; + } + if (!qh->dw_align_buf) { + qh->dw_align_buf = + dwc_dma_alloc_atomic(buf_size, + &qh->dw_align_buf_dma); + if (!qh->dw_align_buf) { + DWC_ERROR("%s: Failed to allocate memory to handle " + "non-dword aligned buffer case\n", __func__); +#ifdef HW2937_WORKAROUND + return 0; +#else + return; +#endif + } + } + if (!hc->ep_is_in) { + dwc_memcpy(qh->dw_align_buf, ptr, hc->xfer_len); + } + hc->align_buff = qh->dw_align_buf_dma; + } + else { + hc->align_buff = 0; + } + + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR || + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { + /* + * This value may be modified when the transfer is started to + * reflect the actual transfer length. + */ + hc->multi_count = dwc_hb_mult(qh->maxp); + } + + if (hcd->core_if->dma_desc_enable) + hc->desc_list_addr = qh->desc_list_dma; + + dwc_otg_hc_init(hcd->core_if, hc); + hc->qh = qh; +#ifdef HW2937_WORKAROUND + hcd->hw2937_assigned_channels |= (1 << hc->hc_num); + DWC_DEBUGPL(DBG_HW2937, " assign %d -> hw2937_ac %x\n", hc->hc_num, hcd->hw2937_assigned_channels); + return 1; +#endif +} + +#ifdef HW2937_WORKAROUND + +void debug_halt(void) +{ + spinlock_t mr_lock = SPIN_LOCK_UNLOCKED; + unsigned long flags; + extern void v6_flush_kern_cache_all(void); + + spin_lock_irqsave(&mr_lock, flags); +#ifdef CONFIG_MACH_BCM2708 + v6_flush_kern_cache_all(); +#endif + while (1) continue; +} + +static +void dwc_otg_hcd_disable_in_channels(dwc_otg_hcd_t * hcd) +{ + int num_channels = hcd->core_if->core_params->host_channels; + static int stall_count = 0; + static int max_stall_count = 1; + static int last_stalled = 0; + int stalled = 0; + int i; + + DWC_DEBUGPL(DBG_HW2937, " Disable In Channels(%x)\n", hcd->hw2937_assigned_channels); + + for (i = 0; i < num_channels; i++) { + if (hcd->hw2937_assigned_channels & (1 << i)) { + dwc_hc_t *hc = hcd->hc_ptr_array[i]; + if (!hc->halt_pending) { + dwc_otg_hc_regs_t *hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num]; + hctsiz_data_t hctsiz; + hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz); + DWC_DEBUGPL(DBG_HW2937, "pktcnt %d, xfersize %x, xfer_len %x\n", hctsiz.b.pktcnt, hctsiz.b.xfersize, hc->xfer_len); + if (hctsiz.b.pktcnt == hc->start_pkt_count) + { + dwc_otg_hc_halt(hcd->core_if, hc, DWC_OTG_HC_XFER_PAUSE_IN); + } + else + { + /* Unless a receive is in progress */ + stalled |= (1< max_stall_count) + { + max_stall_count = stall_count; + DWC_PRINTF( "stall (%x) count -> %d\n", stalled, stall_count); + if (stall_count == 10) + { + debug_halt(); + } + } + } + else + { + stall_count = 0; + last_stalled = stalled; + } +} + +static +int dwc_otg_hcd_update_transaction_mode(dwc_otg_hcd_t * hcd) +{ + dwc_list_link_t *qh_ptr; + dwc_otg_qh_t *qh; + dwc_otg_qtd_t *qtd; + dwc_otg_hcd_urb_t *urb; + int found_in = 0; + + /* If there are any existing out transactions, stay in OUT mode */ + if (hcd->hw2937_xfer_mode == HW2937_XFER_MODE_OUT) + { + return 1; + } + + /* Scan entries in the periodic ready list. */ + qh_ptr = DWC_LIST_FIRST(&hcd->periodic_sched_ready); + + while (qh_ptr != &hcd->periodic_sched_ready) { + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); + urb = qtd->urb; + if (!dwc_otg_hcd_is_pipe_in(&urb->pipe_info)) { + /* Switch to OUT mode */ + switch (hcd->hw2937_xfer_mode) + { + case HW2937_XFER_MODE_IDLE: + DWC_DEBUGPL(DBG_HW2937, "utm -> OUT\n"); + hcd->hw2937_xfer_mode = HW2937_XFER_MODE_OUT; + /* Drop through... */ + case HW2937_XFER_MODE_OUT: + return 1; + case HW2937_XFER_MODE_IN: + DWC_DEBUGPL(DBG_HW2937, "utm - halting %x INs\n", hcd->hw2937_assigned_channels); + /* Disable the channels with outstanding INs */ + dwc_otg_hcd_disable_in_channels(hcd); + + DWC_DEBUGPL(DBG_HW2937, "utm -> PAUSEIN\n"); + hcd->hw2937_xfer_mode = HW2937_XFER_MODE_PAUSEIN; + /* Drop through... */ + case HW2937_XFER_MODE_PAUSEIN: + /* Delay until the halt completes */ + return 0; + } + } + found_in = 1; + qh_ptr = DWC_LIST_NEXT(qh_ptr); + } + + /* + * Scan entries in the inactive portion of the non-periodic + * schedule. + */ + qh_ptr = hcd->non_periodic_sched_inactive.next; + while (qh_ptr != &hcd->non_periodic_sched_inactive) { + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); + urb = qtd->urb; + if (!dwc_otg_hcd_is_pipe_in(&urb->pipe_info)) { + /* Switch to OUT mode */ + switch (hcd->hw2937_xfer_mode) + { + case HW2937_XFER_MODE_IDLE: + DWC_DEBUGPL(DBG_HW2937, "utm -> OUT\n"); + hcd->hw2937_xfer_mode = HW2937_XFER_MODE_OUT; + /* Drop through... */ + case HW2937_XFER_MODE_OUT: + return 1; + case HW2937_XFER_MODE_IN: + DWC_DEBUGPL(DBG_HW2937, "utm - halting %x INs\n", hcd->hw2937_assigned_channels); + /* Disable the channels with outstanding INs */ + dwc_otg_hcd_disable_in_channels(hcd); + + DWC_DEBUGPL(DBG_HW2937, "utm -> PAUSEIN\n"); + hcd->hw2937_xfer_mode = HW2937_XFER_MODE_PAUSEIN; + /* Drop through... */ + case HW2937_XFER_MODE_PAUSEIN: + /* Delay until the halt completes */ + return 0; + } + } + found_in = 1; + qh_ptr = DWC_LIST_NEXT(qh_ptr); + } + + if (found_in && (hcd->hw2937_xfer_mode == HW2937_XFER_MODE_IDLE)) + { + DWC_DEBUGPL(DBG_HW2937, "utm -> IN\n"); + hcd->hw2937_xfer_mode = HW2937_XFER_MODE_IN; + } + return 1; +} + +#endif /* HW2937_WORKAROUND */ + +/** + * This function selects transactions from the HCD transfer schedule and + * assigns them to available host channels. It is called from HCD interrupt + * handler functions. + * + * @param hcd The HCD state structure. + * + * @return The types of new transactions that were assigned to host channels. + */ +dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) +{ + dwc_list_link_t *qh_ptr; + dwc_otg_qh_t *qh; + int num_channels; + dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE; + +#ifdef DEBUG_SOF + DWC_DEBUGPL(DBG_HCD, " Select Transactions\n"); +#endif + +#ifdef HW2937_WORKAROUND + if (!dwc_otg_hcd_update_transaction_mode(hcd)) + { + return ret_val; + } +#endif + + /* Process entries in the periodic ready list. */ + qh_ptr = DWC_LIST_FIRST(&hcd->periodic_sched_ready); + + while (qh_ptr != &hcd->periodic_sched_ready && + !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) { + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); +#ifdef HW2937_WORKAROUND + if (assign_and_init_hc(hcd, qh)) { +#else + assign_and_init_hc(hcd, qh); +#endif + + /* + * Move the QH from the periodic ready schedule to the + * periodic assigned schedule. + */ + qh_ptr = DWC_LIST_NEXT(qh_ptr); + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned, + &qh->qh_list_entry); + + ret_val = DWC_OTG_TRANSACTION_PERIODIC; +#ifdef HW2937_WORKAROUND + } else { + qh_ptr = DWC_LIST_NEXT(qh_ptr); + } +#endif + } + + /* + * Process entries in the inactive portion of the non-periodic + * schedule. Some free host channels may not be used if they are + * reserved for periodic transfers. + */ + qh_ptr = hcd->non_periodic_sched_inactive.next; + num_channels = hcd->core_if->core_params->host_channels; + while (qh_ptr != &hcd->non_periodic_sched_inactive && + (hcd->non_periodic_channels < + num_channels - hcd->periodic_channels) && + !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) { + + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); + +#ifdef HW2937_WORKAROUND + if (assign_and_init_hc(hcd, qh)) { +#else + assign_and_init_hc(hcd, qh); +#endif + + /* + * Move the QH from the non-periodic inactive schedule to the + * non-periodic active schedule. + */ + qh_ptr = DWC_LIST_NEXT(qh_ptr); + DWC_LIST_MOVE_HEAD(&hcd->non_periodic_sched_active, + &qh->qh_list_entry); + + if (ret_val == DWC_OTG_TRANSACTION_NONE) { + ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC; + } else { + ret_val = DWC_OTG_TRANSACTION_ALL; + } + + hcd->non_periodic_channels++; +#ifdef HW2937_WORKAROUND + } else { + qh_ptr = DWC_LIST_NEXT(qh_ptr); + } +#endif + } + + return ret_val; +} +/** + * Attempts to queue a single transaction request for a host channel + * associated with either a periodic or non-periodic transfer. This function + * assumes that there is space available in the appropriate request queue. For + * an OUT transfer or SETUP transaction in Slave mode, it checks whether space + * is available in the appropriate Tx FIFO. + * + * @param hcd The HCD state structure. + * @param hc Host channel descriptor associated with either a periodic or + * non-periodic transfer. + * @param fifo_dwords_avail Number of DWORDs available in the periodic Tx + * FIFO for periodic transfers or the non-periodic Tx FIFO for non-periodic + * transfers. + * + * @return 1 if a request is queued and more requests may be needed to + * complete the transfer, 0 if no more requests are required for this + * transfer, -1 if there is insufficient space in the Tx FIFO. + */ +static int queue_transaction(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, uint16_t fifo_dwords_avail) +{ + int retval; + + if (hcd->core_if->dma_enable) { + if (hcd->core_if->dma_desc_enable) { + if (!hc->xfer_started || (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) { + dwc_otg_hcd_start_xfer_ddma(hcd, hc->qh); + hc->qh->ping_state = 0; + } + } + else if (!hc->xfer_started) { + dwc_otg_hc_start_transfer(hcd->core_if, hc); + hc->qh->ping_state = 0; + } + retval = 0; + } else if (hc->halt_pending) { + /* Don't queue a request if the channel has been halted. */ + retval = 0; + } else if (hc->halt_on_queue) { + dwc_otg_hc_halt(hcd->core_if, hc, hc->halt_status); + retval = 0; + } else if (hc->do_ping) { + if (!hc->xfer_started) { + dwc_otg_hc_start_transfer(hcd->core_if, hc); + } + retval = 0; + } else if (!hc->ep_is_in || hc->data_pid_start == DWC_OTG_HC_PID_SETUP) { + if ((fifo_dwords_avail * 4) >= hc->max_packet) { + if (!hc->xfer_started) { + dwc_otg_hc_start_transfer(hcd->core_if, hc); + retval = 1; + } else { + retval = + dwc_otg_hc_continue_transfer(hcd->core_if, + hc); + } + } else { + retval = -1; + } + } else { + if (!hc->xfer_started) { + dwc_otg_hc_start_transfer(hcd->core_if, hc); + retval = 1; + } else { + retval = dwc_otg_hc_continue_transfer(hcd->core_if, hc); + } + } + + return retval; +} + +/** + * Processes periodic channels for the next frame and queues transactions for + * these channels to the DWC_otg controller. After queueing transactions, the + * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions + * to queue as Periodic Tx FIFO or request queue space becomes available. + * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled. + */ +static void process_periodic_channels(dwc_otg_hcd_t * hcd) +{ + hptxsts_data_t tx_status; + dwc_list_link_t *qh_ptr; + dwc_otg_qh_t *qh; + int status; + int no_queue_space = 0; + int no_fifo_space = 0; + + dwc_otg_host_global_regs_t *host_regs; + host_regs = hcd->core_if->host_if->host_global_regs; + + DWC_DEBUGPL(DBG_HCDV, "Queue periodic transactions\n"); +#ifdef DEBUG + tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts); + DWC_DEBUGPL(DBG_HCDV, + " P Tx Req Queue Space Avail (before queue): %d\n", + tx_status.b.ptxqspcavail); + DWC_DEBUGPL(DBG_HCDV, " P Tx FIFO Space Avail (before queue): %d\n", + tx_status.b.ptxfspcavail); +#endif + + qh_ptr = hcd->periodic_sched_assigned.next; + while (qh_ptr != &hcd->periodic_sched_assigned) { + tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts); + if (tx_status.b.ptxqspcavail == 0) { + no_queue_space = 1; + break; + } + + qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); + + /* + * Set a flag if we're queuing high-bandwidth in slave mode. + * The flag prevents any halts to get into the request queue in + * the middle of multiple high-bandwidth packets getting queued. + */ + if (!hcd->core_if->dma_enable && qh->channel->multi_count > 1) { + hcd->core_if->queuing_high_bandwidth = 1; + } + status = + queue_transaction(hcd, qh->channel, + tx_status.b.ptxfspcavail); + if (status < 0) { + no_fifo_space = 1; + break; + } + + /* + * In Slave mode, stay on the current transfer until there is + * nothing more to do or the high-bandwidth request count is + * reached. In DMA mode, only need to queue one request. The + * controller automatically handles multiple packets for + * high-bandwidth transfers. + */ + if (hcd->core_if->dma_enable || status == 0 || + qh->channel->requests == qh->channel->multi_count) { + qh_ptr = qh_ptr->next; + /* + * Move the QH from the periodic assigned schedule to + * the periodic queued schedule. + */ + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_queued, + &qh->qh_list_entry); + + /* done queuing high bandwidth */ + hcd->core_if->queuing_high_bandwidth = 0; + } + } + + if (!hcd->core_if->dma_enable) { + dwc_otg_core_global_regs_t *global_regs; + gintmsk_data_t intr_mask = {.d32 = 0 }; + + global_regs = hcd->core_if->core_global_regs; + intr_mask.b.ptxfempty = 1; +#ifdef DEBUG + tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts); + DWC_DEBUGPL(DBG_HCDV, + " P Tx Req Queue Space Avail (after queue): %d\n", + tx_status.b.ptxqspcavail); + DWC_DEBUGPL(DBG_HCDV, + " P Tx FIFO Space Avail (after queue): %d\n", + tx_status.b.ptxfspcavail); +#endif + if (!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned) || + no_queue_space || no_fifo_space) { + /* + * May need to queue more transactions as the request + * queue or Tx FIFO empties. Enable the periodic Tx + * FIFO empty interrupt. (Always use the half-empty + * level to ensure that new requests are loaded as + * soon as possible.) + */ + dwc_modify_reg32(&global_regs->gintmsk, 0, + intr_mask.d32); + } else { + /* + * Disable the Tx FIFO empty interrupt since there are + * no more transactions that need to be queued right + * now. This function is called from interrupt + * handlers to queue more transactions as transfer + * states change. + */ + dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, + 0); + } + } +} + +/** + * Processes active non-periodic channels and queues transactions for these + * channels to the DWC_otg controller. After queueing transactions, the NP Tx + * FIFO Empty interrupt is enabled if there are more transactions to queue as + * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx + * FIFO Empty interrupt is disabled. + */ +static void process_non_periodic_channels(dwc_otg_hcd_t * hcd) +{ + gnptxsts_data_t tx_status; + dwc_list_link_t *orig_qh_ptr; + dwc_otg_qh_t *qh; + int status; + int no_queue_space = 0; + int no_fifo_space = 0; + int more_to_do = 0; + + dwc_otg_core_global_regs_t *global_regs = + hcd->core_if->core_global_regs; + + DWC_DEBUGPL(DBG_HCDV, "Queue non-periodic transactions\n"); +#ifdef DEBUG + tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts); + DWC_DEBUGPL(DBG_HCDV, + " NP Tx Req Queue Space Avail (before queue): %d\n", + tx_status.b.nptxqspcavail); + DWC_DEBUGPL(DBG_HCDV, " NP Tx FIFO Space Avail (before queue): %d\n", + tx_status.b.nptxfspcavail); +#endif + /* + * Keep track of the starting point. Skip over the start-of-list + * entry. + */ + if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) { + hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next; + } + orig_qh_ptr = hcd->non_periodic_qh_ptr; + + /* + * Process once through the active list or until no more space is + * available in the request queue or the Tx FIFO. + */ + do { + tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts); + if (!hcd->core_if->dma_enable && tx_status.b.nptxqspcavail == 0) { + no_queue_space = 1; + break; + } + + qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t, + qh_list_entry); + status = + queue_transaction(hcd, qh->channel, + tx_status.b.nptxfspcavail); + + if (status > 0) { + more_to_do = 1; + } else if (status < 0) { + no_fifo_space = 1; + break; + } + + /* Advance to next QH, skipping start-of-list entry. */ + hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next; + if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) { + hcd->non_periodic_qh_ptr = + hcd->non_periodic_qh_ptr->next; + } + + } while (hcd->non_periodic_qh_ptr != orig_qh_ptr); + + if (!hcd->core_if->dma_enable) { + gintmsk_data_t intr_mask = {.d32 = 0 }; + intr_mask.b.nptxfempty = 1; + +#ifdef DEBUG + tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts); + DWC_DEBUGPL(DBG_HCDV, + " NP Tx Req Queue Space Avail (after queue): %d\n", + tx_status.b.nptxqspcavail); + DWC_DEBUGPL(DBG_HCDV, + " NP Tx FIFO Space Avail (after queue): %d\n", + tx_status.b.nptxfspcavail); +#endif + if (more_to_do || no_queue_space || no_fifo_space) { + /* + * May need to queue more transactions as the request + * queue or Tx FIFO empties. Enable the non-periodic + * Tx FIFO empty interrupt. (Always use the half-empty + * level to ensure that new requests are loaded as + * soon as possible.) + */ + dwc_modify_reg32(&global_regs->gintmsk, 0, + intr_mask.d32); + } else { + /* + * Disable the Tx FIFO empty interrupt since there are + * no more transactions that need to be queued right + * now. This function is called from interrupt + * handlers to queue more transactions as transfer + * states change. + */ + dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, + 0); + } + } +} + +/** + * This function processes the currently active host channels and queues + * transactions for these channels to the DWC_otg controller. It is called + * from HCD interrupt handler functions. + * + * @param hcd The HCD state structure. + * @param tr_type The type(s) of transactions to queue (non-periodic, + * periodic, or both). + */ +void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd, + dwc_otg_transaction_type_e tr_type) +{ +#ifdef DEBUG_SOF + DWC_DEBUGPL(DBG_HCD, "Queue Transactions\n"); +#endif + /* Process host channels associated with periodic transfers. */ + if ((tr_type == DWC_OTG_TRANSACTION_PERIODIC || + tr_type == DWC_OTG_TRANSACTION_ALL) && + !DWC_LIST_EMPTY(&hcd->periodic_sched_assigned)) { + + process_periodic_channels(hcd); + } + + /* Process host channels associated with non-periodic transfers. */ + if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC || + tr_type == DWC_OTG_TRANSACTION_ALL) { + if (!DWC_LIST_EMPTY(&hcd->non_periodic_sched_active)) { + process_non_periodic_channels(hcd); + } else { + /* + * Ensure NP Tx FIFO empty interrupt is disabled when + * there are no non-periodic transfers to process. + */ + gintmsk_data_t gintmsk = {.d32 = 0 }; + gintmsk.b.nptxfempty = 1; + dwc_modify_reg32(&hcd->core_if->core_global_regs-> + gintmsk, gintmsk.d32, 0); + } + } +} + +#ifdef DWC_HS_ELECT_TST +/* + * Quick and dirty hack to implement the HS Electrical Test + * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature. + * + * This code was copied from our userspace app "hset". It sends a + * Get Device Descriptor control sequence in two parts, first the + * Setup packet by itself, followed some time later by the In and + * Ack packets. Rather than trying to figure out how to add this + * functionality to the normal driver code, we just hijack the + * hardware, using these two function to drive the hardware + * directly. + */ + +static dwc_otg_core_global_regs_t *global_regs; +static dwc_otg_host_global_regs_t *hc_global_regs; +static dwc_otg_hc_regs_t *hc_regs; +static uint32_t *data_fifo; + +static void do_setup(void) +{ + gintsts_data_t gintsts; + hctsiz_data_t hctsiz; + hcchar_data_t hcchar; + haint_data_t haint; + hcint_data_t hcint; + + /* Enable HAINTs */ + dwc_write_reg32(&hc_global_regs->haintmsk, 0x0001); + + /* Enable HCINTs */ + dwc_write_reg32(&hc_regs->hcintmsk, 0x04a3); + + /* Read GINTSTS */ + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); + + /* Read HAINT */ + haint.d32 = dwc_read_reg32(&hc_global_regs->haint); + + /* Read HCINT */ + hcint.d32 = dwc_read_reg32(&hc_regs->hcint); + + /* Read HCCHAR */ + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + + /* Clear HCINT */ + dwc_write_reg32(&hc_regs->hcint, hcint.d32); + + /* Clear HAINT */ + dwc_write_reg32(&hc_global_regs->haint, haint.d32); + + /* Clear GINTSTS */ + dwc_write_reg32(&global_regs->gintsts, gintsts.d32); + + /* Read GINTSTS */ + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); + + /* + * Send Setup packet (Get Device Descriptor) + */ + + /* Make sure channel is disabled */ + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + if (hcchar.b.chen) { + hcchar.b.chdis = 1; +// hcchar.b.chen = 1; + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); + //sleep(1); + dwc_mdelay(1000); + + /* Read GINTSTS */ + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); + + /* Read HAINT */ + haint.d32 = dwc_read_reg32(&hc_global_regs->haint); + + /* Read HCINT */ + hcint.d32 = dwc_read_reg32(&hc_regs->hcint); + + /* Read HCCHAR */ + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + + /* Clear HCINT */ + dwc_write_reg32(&hc_regs->hcint, hcint.d32); + + /* Clear HAINT */ + dwc_write_reg32(&hc_global_regs->haint, haint.d32); + + /* Clear GINTSTS */ + dwc_write_reg32(&global_regs->gintsts, gintsts.d32); + + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + } + + /* Set HCTSIZ */ + hctsiz.d32 = 0; + hctsiz.b.xfersize = 8; + hctsiz.b.pktcnt = 1; + hctsiz.b.pid = DWC_OTG_HC_PID_SETUP; + dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); + + /* Set HCCHAR */ + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL; + hcchar.b.epdir = 0; + hcchar.b.epnum = 0; + hcchar.b.mps = 8; + hcchar.b.chen = 1; + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); + + /* Fill FIFO with Setup data for Get Device Descriptor */ + data_fifo = (uint32_t *) ((char *)global_regs + 0x1000); + dwc_write_reg32(data_fifo++, 0x01000680); + dwc_write_reg32(data_fifo++, 0x00080000); + + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); + + /* Wait for host channel interrupt */ + do { + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); + } while (gintsts.b.hcintr == 0); + + + /* Disable HCINTs */ + dwc_write_reg32(&hc_regs->hcintmsk, 0x0000); + + /* Disable HAINTs */ + dwc_write_reg32(&hc_global_regs->haintmsk, 0x0000); + + /* Read HAINT */ + haint.d32 = dwc_read_reg32(&hc_global_regs->haint); + + /* Read HCINT */ + hcint.d32 = dwc_read_reg32(&hc_regs->hcint); + + /* Read HCCHAR */ + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + + /* Clear HCINT */ + dwc_write_reg32(&hc_regs->hcint, hcint.d32); + + /* Clear HAINT */ + dwc_write_reg32(&hc_global_regs->haint, haint.d32); + + /* Clear GINTSTS */ + dwc_write_reg32(&global_regs->gintsts, gintsts.d32); + + /* Read GINTSTS */ + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); +} + +static void do_in_ack(void) +{ + gintsts_data_t gintsts; + hctsiz_data_t hctsiz; + hcchar_data_t hcchar; + haint_data_t haint; + hcint_data_t hcint; + host_grxsts_data_t grxsts; + + /* Enable HAINTs */ + dwc_write_reg32(&hc_global_regs->haintmsk, 0x0001); + + /* Enable HCINTs */ + dwc_write_reg32(&hc_regs->hcintmsk, 0x04a3); + + /* Read GINTSTS */ + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); + + /* Read HAINT */ + haint.d32 = dwc_read_reg32(&hc_global_regs->haint); + + /* Read HCINT */ + hcint.d32 = dwc_read_reg32(&hc_regs->hcint); + + /* Read HCCHAR */ + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + + /* Clear HCINT */ + dwc_write_reg32(&hc_regs->hcint, hcint.d32); + + /* Clear HAINT */ + dwc_write_reg32(&hc_global_regs->haint, haint.d32); + + /* Clear GINTSTS */ + dwc_write_reg32(&global_regs->gintsts, gintsts.d32); + + /* Read GINTSTS */ + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); + + /* + * Receive Control In packet + */ + + /* Make sure channel is disabled */ + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + if (hcchar.b.chen) { + hcchar.b.chdis = 1; + hcchar.b.chen = 1; + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); + //sleep(1); + dwc_mdelay(1000); + + /* Read GINTSTS */ + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); + + /* Read HAINT */ + haint.d32 = dwc_read_reg32(&hc_global_regs->haint); + + /* Read HCINT */ + hcint.d32 = dwc_read_reg32(&hc_regs->hcint); + + /* Read HCCHAR */ + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + + /* Clear HCINT */ + dwc_write_reg32(&hc_regs->hcint, hcint.d32); + + /* Clear HAINT */ + dwc_write_reg32(&hc_global_regs->haint, haint.d32); + + /* Clear GINTSTS */ + dwc_write_reg32(&global_regs->gintsts, gintsts.d32); + + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + } + + /* Set HCTSIZ */ + hctsiz.d32 = 0; + hctsiz.b.xfersize = 8; + hctsiz.b.pktcnt = 1; + hctsiz.b.pid = DWC_OTG_HC_PID_DATA1; + dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); + + /* Set HCCHAR */ + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL; + hcchar.b.epdir = 1; + hcchar.b.epnum = 0; + hcchar.b.mps = 8; + hcchar.b.chen = 1; + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); + + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); + + /* Wait for receive status queue interrupt */ + do { + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); + } while (gintsts.b.rxstsqlvl == 0); + + + /* Read RXSTS */ + grxsts.d32 = dwc_read_reg32(&global_regs->grxstsp); + + /* Clear RXSTSQLVL in GINTSTS */ + gintsts.d32 = 0; + gintsts.b.rxstsqlvl = 1; + dwc_write_reg32(&global_regs->gintsts, gintsts.d32); + + switch (grxsts.b.pktsts) { + case DWC_GRXSTS_PKTSTS_IN: + /* Read the data into the host buffer */ + if (grxsts.b.bcnt > 0) { + int i; + int word_count = (grxsts.b.bcnt + 3) / 4; + + data_fifo = (uint32_t *) ((char *)global_regs + 0x1000); + + for (i = 0; i < word_count; i++) { + (void)dwc_read_reg32(data_fifo++); + } + } + break; + + default: + break; + } + + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); + + /* Wait for receive status queue interrupt */ + do { + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); + } while (gintsts.b.rxstsqlvl == 0); + + + /* Read RXSTS */ + grxsts.d32 = dwc_read_reg32(&global_regs->grxstsp); + + /* Clear RXSTSQLVL in GINTSTS */ + gintsts.d32 = 0; + gintsts.b.rxstsqlvl = 1; + dwc_write_reg32(&global_regs->gintsts, gintsts.d32); + + switch (grxsts.b.pktsts) { + case DWC_GRXSTS_PKTSTS_IN_XFER_COMP: + break; + + default: + break; + } + + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); + + /* Wait for host channel interrupt */ + do { + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); + } while (gintsts.b.hcintr == 0); + + + /* Read HAINT */ + haint.d32 = dwc_read_reg32(&hc_global_regs->haint); + + /* Read HCINT */ + hcint.d32 = dwc_read_reg32(&hc_regs->hcint); + + /* Read HCCHAR */ + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + + /* Clear HCINT */ + dwc_write_reg32(&hc_regs->hcint, hcint.d32); + + /* Clear HAINT */ + dwc_write_reg32(&hc_global_regs->haint, haint.d32); + + /* Clear GINTSTS */ + dwc_write_reg32(&global_regs->gintsts, gintsts.d32); + + /* Read GINTSTS */ + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); + +// usleep(100000); +// mdelay(100); + dwc_mdelay(1); + + /* + * Send handshake packet + */ + + /* Read HAINT */ + haint.d32 = dwc_read_reg32(&hc_global_regs->haint); + + /* Read HCINT */ + hcint.d32 = dwc_read_reg32(&hc_regs->hcint); + + /* Read HCCHAR */ + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + + /* Clear HCINT */ + dwc_write_reg32(&hc_regs->hcint, hcint.d32); + + /* Clear HAINT */ + dwc_write_reg32(&hc_global_regs->haint, haint.d32); + + /* Clear GINTSTS */ + dwc_write_reg32(&global_regs->gintsts, gintsts.d32); + + /* Read GINTSTS */ + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); + + /* Make sure channel is disabled */ + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + if (hcchar.b.chen) { + hcchar.b.chdis = 1; + hcchar.b.chen = 1; + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); + //sleep(1); + dwc_mdelay(1000); + + /* Read GINTSTS */ + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); + + /* Read HAINT */ + haint.d32 = dwc_read_reg32(&hc_global_regs->haint); + + /* Read HCINT */ + hcint.d32 = dwc_read_reg32(&hc_regs->hcint); + + /* Read HCCHAR */ + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + + /* Clear HCINT */ + dwc_write_reg32(&hc_regs->hcint, hcint.d32); + + /* Clear HAINT */ + dwc_write_reg32(&hc_global_regs->haint, haint.d32); + + /* Clear GINTSTS */ + dwc_write_reg32(&global_regs->gintsts, gintsts.d32); + + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + } + + /* Set HCTSIZ */ + hctsiz.d32 = 0; + hctsiz.b.xfersize = 0; + hctsiz.b.pktcnt = 1; + hctsiz.b.pid = DWC_OTG_HC_PID_DATA1; + dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); + + /* Set HCCHAR */ + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL; + hcchar.b.epdir = 0; + hcchar.b.epnum = 0; + hcchar.b.mps = 8; + hcchar.b.chen = 1; + dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); + + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); + + /* Wait for host channel interrupt */ + do { + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); + } while (gintsts.b.hcintr == 0); + + + /* Disable HCINTs */ + dwc_write_reg32(&hc_regs->hcintmsk, 0x0000); + + /* Disable HAINTs */ + dwc_write_reg32(&hc_global_regs->haintmsk, 0x0000); + + /* Read HAINT */ + haint.d32 = dwc_read_reg32(&hc_global_regs->haint); + + /* Read HCINT */ + hcint.d32 = dwc_read_reg32(&hc_regs->hcint); + + /* Read HCCHAR */ + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + + /* Clear HCINT */ + dwc_write_reg32(&hc_regs->hcint, hcint.d32); + + /* Clear HAINT */ + dwc_write_reg32(&hc_global_regs->haint, haint.d32); + + /* Clear GINTSTS */ + dwc_write_reg32(&global_regs->gintsts, gintsts.d32); + + /* Read GINTSTS */ + gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); +} +#endif + +/** Handles hub class-specific requests. */ +int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd, + uint16_t typeReq, + uint16_t wValue, + uint16_t wIndex, uint8_t * buf, uint16_t wLength) +{ + int retval = 0; + + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if; + usb_hub_descriptor_t *hub_desc; + hprt0_data_t hprt0 = {.d32 = 0 }; + + uint32_t port_status; + + switch (typeReq) { + case UCR_CLEAR_HUB_FEATURE: + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " + "ClearHubFeature 0x%x\n", wValue); + switch (wValue) { + case UHF_C_HUB_LOCAL_POWER: + case UHF_C_HUB_OVER_CURRENT: + /* Nothing required here */ + break; + default: + retval = -DWC_E_INVALID; + DWC_ERROR("DWC OTG HCD - " + "ClearHubFeature request %xh unknown\n", + wValue); + } + break; + case UCR_CLEAR_PORT_FEATURE: +#ifdef CONFIG_USB_DWC_OTG_LPM + if (wValue != UHF_PORT_L1) +#endif + if (!wIndex || wIndex > 1) + goto error; + + switch (wValue) { + case UHF_PORT_ENABLE: + DWC_DEBUGPL(DBG_ANY, "DWC OTG HCD HUB CONTROL - " + "ClearPortFeature USB_PORT_FEAT_ENABLE\n"); + hprt0.d32 = dwc_otg_read_hprt0(core_if); + hprt0.b.prtena = 1; + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); + break; + case UHF_PORT_SUSPEND: + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " + "ClearPortFeature USB_PORT_FEAT_SUSPEND\n"); + + dwc_write_reg32(core_if->pcgcctl, 0); + dwc_mdelay(5); + + hprt0.d32 = dwc_otg_read_hprt0(core_if); + hprt0.b.prtres = 1; + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); + hprt0.b.prtsusp = 0; + /* Clear Resume bit */ + dwc_mdelay(100); + hprt0.b.prtres = 0; + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); + break; +#ifdef CONFIG_USB_DWC_OTG_LPM + case UHF_PORT_L1: + { + pcgcctl_data_t pcgcctl = {.d32 = 0 }; + glpmcfg_data_t lpmcfg = {.d32 = 0 }; + + lpmcfg.d32 = + dwc_read_reg32(&core_if->core_global_regs-> + glpmcfg); + lpmcfg.b.en_utmi_sleep = 0; + lpmcfg.b.hird_thres &= (~(1 << 4)); + lpmcfg.b.prt_sleep_sts = 1; + dwc_write_reg32(&core_if->core_global_regs-> + glpmcfg, lpmcfg.d32); + + /* Clear Enbl_L1Gating bit. */ + pcgcctl.b.enbl_sleep_gating = 1; + dwc_modify_reg32(core_if->pcgcctl, pcgcctl.d32, + 0); + + dwc_mdelay(5); + + hprt0.d32 = dwc_otg_read_hprt0(core_if); + hprt0.b.prtres = 1; + dwc_write_reg32(core_if->host_if->hprt0, + hprt0.d32); + /* This bit will be cleared in wakeup interrupt handle */ + break; + } +#endif + case UHF_PORT_POWER: + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " + "ClearPortFeature USB_PORT_FEAT_POWER\n"); + hprt0.d32 = dwc_otg_read_hprt0(core_if); + hprt0.b.prtpwr = 0; + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); + break; + case UHF_PORT_INDICATOR: + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " + "ClearPortFeature USB_PORT_FEAT_INDICATOR\n"); + /* Port inidicator not supported */ + break; + case UHF_C_PORT_CONNECTION: + /* Clears drivers internal connect status change + * flag */ + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " + "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n"); + dwc_otg_hcd->flags.b.port_connect_status_change = 0; + break; + case UHF_C_PORT_RESET: + /* Clears the driver's internal Port Reset Change + * flag */ + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " + "ClearPortFeature USB_PORT_FEAT_C_RESET\n"); + dwc_otg_hcd->flags.b.port_reset_change = 0; + break; + case UHF_C_PORT_ENABLE: + /* Clears the driver's internal Port + * Enable/Disable Change flag */ + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " + "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n"); + dwc_otg_hcd->flags.b.port_enable_change = 0; + break; + case UHF_C_PORT_SUSPEND: + /* Clears the driver's internal Port Suspend + * Change flag, which is set when resume signaling on + * the host port is complete */ + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " + "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n"); + dwc_otg_hcd->flags.b.port_suspend_change = 0; + break; +#ifdef CONFIG_USB_DWC_OTG_LPM + case UHF_C_PORT_L1: + dwc_otg_hcd->flags.b.port_l1_change = 0; + break; +#endif + case UHF_C_PORT_OVER_CURRENT: + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " + "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n"); + dwc_otg_hcd->flags.b.port_over_current_change = 0; + break; + default: + retval = -DWC_E_INVALID; + DWC_ERROR("DWC OTG HCD - " + "ClearPortFeature request %xh " + "unknown or unsupported\n", wValue); + } + break; + case UCR_GET_HUB_DESCRIPTOR: + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " + "GetHubDescriptor\n"); + hub_desc = (usb_hub_descriptor_t *) buf; + hub_desc->bDescLength = 9; + hub_desc->bDescriptorType = 0x29; + hub_desc->bNbrPorts = 1; + USETW(hub_desc->wHubCharacteristics, 0x08); + hub_desc->bPwrOn2PwrGood = 1; + hub_desc->bHubContrCurrent = 0; + hub_desc->DeviceRemovable[0] = 0; + hub_desc->DeviceRemovable[1] = 0xff; + break; + case UCR_GET_HUB_STATUS: + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " + "GetHubStatus\n"); + DWC_MEMSET(buf, 0, 4); + break; + case UCR_GET_PORT_STATUS: + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " + "GetPortStatus\n"); + if (!wIndex || wIndex > 1) + goto error; + + port_status = 0; + + if (dwc_otg_hcd->flags.b.port_connect_status_change) + port_status |= (1 << UHF_C_PORT_CONNECTION); + + if (dwc_otg_hcd->flags.b.port_enable_change) + port_status |= (1 << UHF_C_PORT_ENABLE); + + if (dwc_otg_hcd->flags.b.port_suspend_change) + port_status |= (1 << UHF_C_PORT_SUSPEND); + + if (dwc_otg_hcd->flags.b.port_l1_change) + port_status |= (1 << UHF_C_PORT_L1); + + if (dwc_otg_hcd->flags.b.port_reset_change) { + port_status |= (1 << UHF_C_PORT_RESET); + } + + if (dwc_otg_hcd->flags.b.port_over_current_change) { + DWC_ERROR("Device Not Supported\n"); + port_status |= (1 << UHF_C_PORT_OVER_CURRENT); + } + + if (!dwc_otg_hcd->flags.b.port_connect_status) { + /* + * The port is disconnected, which means the core is + * either in device mode or it soon will be. Just + * return 0's for the remainder of the port status + * since the port register can't be read if the core + * is in device mode. + */ + *((__le32 *) buf) = dwc_cpu_to_le32(&port_status); + break; + } + + hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0); + DWC_DEBUGPL(DBG_HCDV, " HPRT0: 0x%08x\n", hprt0.d32); + + if (hprt0.b.prtconnsts) + port_status |= (1 << UHF_PORT_CONNECTION); + + if (hprt0.b.prtena) + port_status |= (1 << UHF_PORT_ENABLE); + + if (hprt0.b.prtsusp) + port_status |= (1 << UHF_PORT_SUSPEND); + + if (hprt0.b.prtovrcurract) + port_status |= (1 << UHF_PORT_OVER_CURRENT); + + if (hprt0.b.prtrst) + port_status |= (1 << UHF_PORT_RESET); + + if (hprt0.b.prtpwr) + port_status |= (1 << UHF_PORT_POWER); + + if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) + port_status |= (1 << UHF_PORT_HIGH_SPEED); + else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED) + port_status |= (1 << UHF_PORT_LOW_SPEED); + + if (hprt0.b.prttstctl) + port_status |= (1 << UHF_PORT_TEST); + if (dwc_otg_get_lpm_portsleepstatus(dwc_otg_hcd->core_if)) { + port_status |= (1 << UHF_PORT_L1); + } + + /* USB_PORT_FEAT_INDICATOR unsupported always 0 */ + + *((__le32 *) buf) = dwc_cpu_to_le32(&port_status); + + break; + case UCR_SET_HUB_FEATURE: + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " + "SetHubFeature\n"); + /* No HUB features supported */ + break; + case UCR_SET_PORT_FEATURE: + if (wValue != UHF_PORT_TEST && (!wIndex || wIndex > 1)) + goto error; + + if (!dwc_otg_hcd->flags.b.port_connect_status) { + /* + * The port is disconnected, which means the core is + * either in device mode or it soon will be. Just + * return without doing anything since the port + * register can't be written if the core is in device + * mode. + */ + break; + } + + switch (wValue) { + case UHF_PORT_SUSPEND: + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " + "SetPortFeature - USB_PORT_FEAT_SUSPEND\n"); + if (dwc_otg_hcd_otg_port(dwc_otg_hcd) == wIndex && + dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) { + gotgctl_data_t gotgctl = {.d32 = 0 }; + gotgctl.b.hstsethnpen = 1; + dwc_modify_reg32(&core_if->core_global_regs-> + gotgctl, 0, gotgctl.d32); + core_if->op_state = A_SUSPEND; + } + hprt0.d32 = dwc_otg_read_hprt0(core_if); + hprt0.b.prtsusp = 1; + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); + { + uint64_t flags; + /* Update lx_state */ + DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags); + core_if->lx_state = DWC_OTG_L2; + DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags); + } + /* Suspend the Phy Clock */ + { + pcgcctl_data_t pcgcctl = {.d32 = 0 }; + pcgcctl.b.stoppclk = 1; + dwc_modify_reg32(core_if->pcgcctl, 0, + pcgcctl.d32); + } + + /* For HNP the bus must be suspended for at least 200ms. */ + if (dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) { + dwc_mdelay(200); + } + break; + case UHF_PORT_POWER: + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " + "SetPortFeature - USB_PORT_FEAT_POWER\n"); + hprt0.d32 = dwc_otg_read_hprt0(core_if); + hprt0.b.prtpwr = 1; + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); + break; + case UHF_PORT_RESET: + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " + "SetPortFeature - USB_PORT_FEAT_RESET\n"); + { + pcgcctl_data_t pcgcctl = {.d32 = 0 }; + pcgcctl.b.enbl_sleep_gating = 1; + pcgcctl.b.stoppclk = 1; + dwc_modify_reg32(core_if->pcgcctl, pcgcctl.d32, + 0); + dwc_write_reg32(core_if->pcgcctl, 0); + } +#ifdef CONFIG_USB_DWC_OTG_LPM + { + glpmcfg_data_t lpmcfg; + lpmcfg.d32 = + dwc_read_reg32(&core_if->core_global_regs-> + glpmcfg); + if (lpmcfg.b.prt_sleep_sts) { + lpmcfg.b.en_utmi_sleep = 0; + lpmcfg.b.hird_thres &= (~(1 << 4)); + dwc_write_reg32(&core_if-> + core_global_regs-> + glpmcfg, lpmcfg.d32); + dwc_mdelay(1); + } + } +#endif + hprt0.d32 = dwc_otg_read_hprt0(core_if); + /* When B-Host the Port reset bit is set in + * the Start HCD Callback function, so that + * the reset is started within 1ms of the HNP + * success interrupt. */ + if (!dwc_otg_hcd_is_b_host(dwc_otg_hcd)) { + hprt0.b.prtrst = 1; + dwc_write_reg32(core_if->host_if->hprt0, + hprt0.d32); + } + /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */ + dwc_mdelay(60); + hprt0.b.prtrst = 0; + dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); + core_if->lx_state = DWC_OTG_L0; /* Now back to the on state */ + break; +#ifdef DWC_HS_ELECT_TST + case UHF_PORT_TEST: + { + uint32_t t; + gintmsk_data_t gintmsk; + + t = (wIndex >> 8); /* MSB wIndex USB */ + DWC_DEBUGPL(DBG_HCD, + "DWC OTG HCD HUB CONTROL - " + "SetPortFeature - USB_PORT_FEAT_TEST %d\n", + t); + DWC_WARN("USB_PORT_FEAT_TEST %d\n", t); + if (t < 6) { + hprt0.d32 = dwc_otg_read_hprt0(core_if); + hprt0.b.prttstctl = t; + dwc_write_reg32(core_if->host_if->hprt0, + hprt0.d32); + } else { + /* Setup global vars with reg addresses (quick and + * dirty hack, should be cleaned up) + */ + global_regs = core_if->core_global_regs; + hc_global_regs = + core_if->host_if->host_global_regs; + hc_regs = + (dwc_otg_hc_regs_t *) ((char *) + global_regs + + 0x500); + data_fifo = + (uint32_t *) ((char *)global_regs + + 0x1000); + + if (t == 6) { /* HS_HOST_PORT_SUSPEND_RESUME */ + /* Save current interrupt mask */ + gintmsk.d32 = + dwc_read_reg32 + (&global_regs->gintmsk); + + /* Disable all interrupts while we muck with + * the hardware directly + */ + dwc_write_reg32(&global_regs-> + gintmsk, 0); + + /* 15 second delay per the test spec */ + dwc_mdelay(15000); + + /* Drive suspend on the root port */ + hprt0.d32 = + dwc_otg_read_hprt0(core_if); + hprt0.b.prtsusp = 1; + hprt0.b.prtres = 0; + dwc_write_reg32(core_if-> + host_if->hprt0, + hprt0.d32); + + /* 15 second delay per the test spec */ + dwc_mdelay(15000); + + /* Drive resume on the root port */ + hprt0.d32 = + dwc_otg_read_hprt0(core_if); + hprt0.b.prtsusp = 0; + hprt0.b.prtres = 1; + dwc_write_reg32(core_if-> + host_if->hprt0, + hprt0.d32); + dwc_mdelay(100); + + /* Clear the resume bit */ + hprt0.b.prtres = 0; + dwc_write_reg32(core_if-> + host_if->hprt0, + hprt0.d32); + + /* Restore interrupts */ + dwc_write_reg32(&global_regs-> + gintmsk, + gintmsk.d32); + } else if (t == 7) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */ + /* Save current interrupt mask */ + gintmsk.d32 = + dwc_read_reg32 + (&global_regs->gintmsk); + + /* Disable all interrupts while we muck with + * the hardware directly + */ + dwc_write_reg32(&global_regs-> + gintmsk, 0); + + /* 15 second delay per the test spec */ + dwc_mdelay(15000); + + /* Send the Setup packet */ + do_setup(); + + /* 15 second delay so nothing else happens for awhile */ + dwc_mdelay(15000); + + /* Restore interrupts */ + dwc_write_reg32(&global_regs-> + gintmsk, + gintmsk.d32); + } else if (t == 8) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */ + /* Save current interrupt mask */ + gintmsk.d32 = + dwc_read_reg32 + (&global_regs->gintmsk); + + /* Disable all interrupts while we muck with + * the hardware directly + */ + dwc_write_reg32(&global_regs-> + gintmsk, 0); + + /* Send the Setup packet */ + do_setup(); + + /* 15 second delay so nothing else happens for awhile */ + dwc_mdelay(15000); + + /* Send the In and Ack packets */ + do_in_ack(); + + /* 15 second delay so nothing else happens for awhile */ + dwc_mdelay(15000); + + /* Restore interrupts */ + dwc_write_reg32(&global_regs-> + gintmsk, + gintmsk.d32); + } + } + break; + } +#endif /* DWC_HS_ELECT_TST */ + + case UHF_PORT_INDICATOR: + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " + "SetPortFeature - USB_PORT_FEAT_INDICATOR\n"); + /* Not supported */ + break; + default: + retval = -DWC_E_INVALID; + DWC_ERROR("DWC OTG HCD - " + "SetPortFeature request %xh " + "unknown or unsupported\n", wValue); + break; + } + break; +#ifdef CONFIG_USB_DWC_OTG_LPM + case UCR_SET_AND_TEST_PORT_FEATURE: + if (wValue != UHF_PORT_L1) { + goto error; + } + { + int portnum, hird, devaddr, remwake; + glpmcfg_data_t lpmcfg; + uint32_t time_usecs; + gintsts_data_t gintsts; + gintmsk_data_t gintmsk; + + if (!dwc_otg_get_param_lpm_enable(core_if)) { + goto error; + } + if (wValue != UHF_PORT_L1 || wLength != 1) { + goto error; + } + /* Check if the port currently is in SLEEP state */ + lpmcfg.d32 = + dwc_read_reg32(&core_if->core_global_regs->glpmcfg); + if (lpmcfg.b.prt_sleep_sts) { + DWC_INFO("Port is already in sleep mode\n"); + buf[0] = 0; /* Return success */ + break; + } + + portnum = wIndex & 0xf; + hird = (wIndex >> 4) & 0xf; + devaddr = (wIndex >> 8) & 0x7f; + remwake = (wIndex >> 15); + + if (portnum != 1) { + retval = -DWC_E_INVALID; + DWC_WARN + ("Wrong port number(%d) in SetandTestPortFeature request\n", + portnum); + break; + } + + DWC_PRINTF + ("SetandTestPortFeature request: portnum = %d, hird = %d, devaddr = %d, rewake = %d\n", + portnum, hird, devaddr, remwake); + /* Disable LPM interrupt */ + gintmsk.d32 = 0; + gintmsk.b.lpmtranrcvd = 1; + dwc_modify_reg32(&core_if->core_global_regs->gintmsk, + gintmsk.d32, 0); + + if (dwc_otg_hcd_send_lpm + (dwc_otg_hcd, devaddr, hird, remwake)) { + retval = -DWC_E_INVALID; + break; + } + + time_usecs = 10 * (lpmcfg.b.retry_count + 1); + /* We will consider timeout if time_usecs microseconds pass, + * and we don't receive LPM transaction status. + * After receiving non-error responce(ACK/NYET/STALL) from device, + * core will set lpmtranrcvd bit. + */ + do { + gintsts.d32 = + dwc_read_reg32(&core_if->core_global_regs-> + gintsts); + if (gintsts.b.lpmtranrcvd) { + break; + } + dwc_udelay(1); + } while (--time_usecs); + /* lpm_int bit will be cleared in LPM interrupt handler */ + + /* Now fill status + * 0x00 - Success + * 0x10 - NYET + * 0x11 - Timeout + */ + if (!gintsts.b.lpmtranrcvd) { + buf[0] = 0x3; /* Completion code is Timeout */ + dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd); + } else { + lpmcfg.d32 = + dwc_read_reg32(&core_if->core_global_regs-> + glpmcfg); + if (lpmcfg.b.lpm_resp == 0x3) { + /* ACK responce from the device */ + buf[0] = 0x00; /* Success */ + } else if (lpmcfg.b.lpm_resp == 0x2) { + /* NYET responce from the device */ + buf[0] = 0x2; + } else { + /* Otherwise responce with Timeout */ + buf[0] = 0x3; + } + } + DWC_PRINTF("Device responce to LPM trans is %x\n", + lpmcfg.b.lpm_resp); + dwc_modify_reg32(&core_if->core_global_regs->gintmsk, 0, + gintmsk.d32); + + break; + } +#endif /* CONFIG_USB_DWC_OTG_LPM */ + default: + error: + retval = -DWC_E_INVALID; + DWC_WARN("DWC OTG HCD - " + "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n", + typeReq, wIndex, wValue); + break; + } + + return retval; +} + +#ifdef CONFIG_USB_DWC_OTG_LPM +/** Returns index of host channel to perform LPM transaction. */ +int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd, uint8_t devaddr) +{ + dwc_otg_core_if_t *core_if = hcd->core_if; + dwc_hc_t *hc; + hcchar_data_t hcchar; + gintmsk_data_t gintmsk = {.d32 = 0 }; + + if (DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) { + DWC_PRINTF("No free channel to select for LPM transaction\n"); + return -1; + } + + hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list); + + /* Mask host channel interrupts. */ + gintmsk.b.hcintr = 1; + dwc_modify_reg32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0); + + /* Fill fields that core needs for LPM transaction */ + hcchar.b.devaddr = devaddr; + hcchar.b.epnum = 0; + hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL; + hcchar.b.mps = 64; + hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW); + hcchar.b.epdir = 0; /* OUT */ + dwc_write_reg32(&core_if->host_if->hc_regs[hc->hc_num]->hcchar, + hcchar.d32); + + /* Remove the host channel from the free list. */ + DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry); + + DWC_PRINTF("hcnum = %d devaddr = %d\n", hc->hc_num, devaddr); + + return hc->hc_num; +} + +/** Release hc after performing LPM transaction */ +void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd) +{ + dwc_hc_t *hc; + glpmcfg_data_t lpmcfg; + uint8_t hc_num; + + lpmcfg.d32 = dwc_read_reg32(&hcd->core_if->core_global_regs->glpmcfg); + hc_num = lpmcfg.b.lpm_chan_index; + + hc = hcd->hc_ptr_array[hc_num]; + + DWC_PRINTF("Freeing channel %d after LPM\n", hc_num); + /* Return host channel to free list */ + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry); +} + +int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr, uint8_t hird, + uint8_t bRemoteWake) +{ + glpmcfg_data_t lpmcfg; + pcgcctl_data_t pcgcctl = {.d32 = 0 }; + int channel; + + channel = dwc_otg_hcd_get_hc_for_lpm_tran(hcd, devaddr); + if (channel < 0) { + return channel; + } + + pcgcctl.b.enbl_sleep_gating = 1; + dwc_modify_reg32(hcd->core_if->pcgcctl, 0, pcgcctl.d32); + + /* Read LPM config register */ + lpmcfg.d32 = dwc_read_reg32(&hcd->core_if->core_global_regs->glpmcfg); + + /* Program LPM transaction fields */ + lpmcfg.b.rem_wkup_en = bRemoteWake; + lpmcfg.b.hird = hird; + lpmcfg.b.hird_thres = 0x1c; + lpmcfg.b.lpm_chan_index = channel; + lpmcfg.b.en_utmi_sleep = 1; + /* Program LPM config register */ + dwc_write_reg32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32); + + /* Send LPM transaction */ + lpmcfg.b.send_lpm = 1; + dwc_write_reg32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32); + + return 0; +} + +#endif /* CONFIG_USB_DWC_OTG_LPM */ + +int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port) +{ + int retval; + + if (port != 1) { + return -DWC_E_INVALID; + } + + retval = (hcd->flags.b.port_connect_status_change || + hcd->flags.b.port_reset_change || + hcd->flags.b.port_enable_change || + hcd->flags.b.port_suspend_change || + hcd->flags.b.port_over_current_change); +#ifdef DEBUG + if (retval) { + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB STATUS DATA:" + " Root port status changed\n"); + DWC_DEBUGPL(DBG_HCDV, " port_connect_status_change: %d\n", + hcd->flags.b.port_connect_status_change); + DWC_DEBUGPL(DBG_HCDV, " port_reset_change: %d\n", + hcd->flags.b.port_reset_change); + DWC_DEBUGPL(DBG_HCDV, " port_enable_change: %d\n", + hcd->flags.b.port_enable_change); + DWC_DEBUGPL(DBG_HCDV, " port_suspend_change: %d\n", + hcd->flags.b.port_suspend_change); + DWC_DEBUGPL(DBG_HCDV, " port_over_current_change: %d\n", + hcd->flags.b.port_over_current_change); + } +#endif + return retval; +} + +int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * dwc_otg_hcd) +{ + hfnum_data_t hfnum; + hfnum.d32 = dwc_read_reg32(&dwc_otg_hcd->core_if-> + host_if->host_global_regs->hfnum); + +#ifdef DEBUG_SOF + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n", + hfnum.b.frnum); +#endif + return hfnum.b.frnum; +} + +int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd, + struct dwc_otg_hcd_function_ops *fops) +{ + int retval = 0; + + hcd->fops = fops; + if (!dwc_otg_is_device_mode(hcd->core_if)) { + dwc_otg_hcd_reinit(hcd); + } else { + retval = -DWC_E_NO_DEVICE; + } + + return retval; +} + +void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd) +{ + return hcd->priv; +} + +void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data) +{ + hcd->priv = priv_data; +} + +uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd) +{ + return hcd->otg_port; +} + +uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd) +{ + uint32_t is_b_host; + if (hcd->core_if->op_state == B_HOST) { + is_b_host = 1; + } else { + is_b_host = 0; + } + + return is_b_host; +} + +dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd, + int iso_desc_count, int atomic_alloc) +{ + dwc_otg_hcd_urb_t *dwc_otg_urb; + uint32_t size; + + size = + sizeof(*dwc_otg_urb) + + iso_desc_count * sizeof(struct dwc_otg_hcd_iso_packet_desc); + if (atomic_alloc) { + dwc_otg_urb = dwc_alloc_atomic(size); + } else { + dwc_otg_urb = dwc_alloc(size); + } + dwc_otg_urb->packet_count = iso_desc_count; + + return dwc_otg_urb; +} + +void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * dwc_otg_urb, + uint8_t dev_addr, uint8_t ep_num, + uint8_t ep_type, uint8_t ep_dir, uint16_t mps) +{ + dwc_otg_hcd_fill_pipe(&dwc_otg_urb->pipe_info, dev_addr, ep_num, + ep_type, ep_dir, mps); +#if 0 + DWC_PRINTF + ("addr = %d, ep_num = %d, ep_dir = 0x%x, ep_type = 0x%x, mps = %d\n", + dev_addr, ep_num, ep_dir, ep_type, mps); +#endif +} + +void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * dwc_otg_urb, + void *urb_handle, void *buf, dwc_dma_t dma, + uint32_t buflen, void *setup_packet, + dwc_dma_t setup_dma, uint32_t flags, + uint16_t interval) +{ + dwc_otg_urb->priv = urb_handle; + dwc_otg_urb->buf = buf; + dwc_otg_urb->dma = dma; + dwc_otg_urb->length = buflen; + dwc_otg_urb->setup_packet = setup_packet; + dwc_otg_urb->setup_dma = setup_dma; + dwc_otg_urb->flags = flags; + dwc_otg_urb->interval = interval; + dwc_otg_urb->status = -DWC_E_IN_PROGRESS; +} + +uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb) +{ + return dwc_otg_urb->status; +} + +uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t * dwc_otg_urb) +{ + return dwc_otg_urb->actual_length; +} + +uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t * dwc_otg_urb) +{ + return dwc_otg_urb->error_count; +} + +void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb, + int desc_num, uint32_t offset, + uint32_t length) +{ + dwc_otg_urb->iso_descs[desc_num].offset = offset; + dwc_otg_urb->iso_descs[desc_num].length = length; +} + +uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t * dwc_otg_urb, + int desc_num) +{ + return dwc_otg_urb->iso_descs[desc_num].status; +} + +uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t * + dwc_otg_urb, int desc_num) +{ + return dwc_otg_urb->iso_descs[desc_num].actual_length; +} + +int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd, void *ep_handle) +{ + int allocated = 0; + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle; + + if (qh) { + if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) { + allocated = 1; + } + } + return allocated; +} + +int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle) +{ + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle; + int freed = 0; + DWC_ASSERT(qh, "qh is not allocated\n"); + + if (DWC_LIST_EMPTY(&qh->qh_list_entry)) { + freed = 1; + } + + return freed; +} + +uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd, void *ep_handle) +{ + dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle; + DWC_ASSERT(qh, "qh is not allocated\n"); + return qh->usecs; +} + +void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd) +{ +#ifdef DEBUG + int num_channels; + int i; + gnptxsts_data_t np_tx_status; + hptxsts_data_t p_tx_status; + + num_channels = hcd->core_if->core_params->host_channels; + DWC_PRINTF("\n"); + DWC_PRINTF + ("************************************************************\n"); + DWC_PRINTF("HCD State:\n"); + DWC_PRINTF(" Num channels: %d\n", num_channels); + for (i = 0; i < num_channels; i++) { + dwc_hc_t *hc = hcd->hc_ptr_array[i]; + DWC_PRINTF(" Channel %d:\n", i); + DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n", + hc->dev_addr, hc->ep_num, hc->ep_is_in); + DWC_PRINTF(" speed: %d\n", hc->speed); + DWC_PRINTF(" ep_type: %d\n", hc->ep_type); + DWC_PRINTF(" max_packet: %d\n", hc->max_packet); + DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start); + DWC_PRINTF(" multi_count: %d\n", hc->multi_count); + DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started); + DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff); + DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len); + DWC_PRINTF(" xfer_count: %d\n", hc->xfer_count); + DWC_PRINTF(" halt_on_queue: %d\n", hc->halt_on_queue); + DWC_PRINTF(" halt_pending: %d\n", hc->halt_pending); + DWC_PRINTF(" halt_status: %d\n", hc->halt_status); + DWC_PRINTF(" do_split: %d\n", hc->do_split); + DWC_PRINTF(" complete_split: %d\n", hc->complete_split); + DWC_PRINTF(" hub_addr: %d\n", hc->hub_addr); + DWC_PRINTF(" port_addr: %d\n", hc->port_addr); + DWC_PRINTF(" xact_pos: %d\n", hc->xact_pos); + DWC_PRINTF(" requests: %d\n", hc->requests); + DWC_PRINTF(" qh: %p\n", hc->qh); + if (hc->xfer_started) { + hfnum_data_t hfnum; + hcchar_data_t hcchar; + hctsiz_data_t hctsiz; + hcint_data_t hcint; + hcintmsk_data_t hcintmsk; + hfnum.d32 = + dwc_read_reg32(&hcd->core_if->host_if-> + host_global_regs->hfnum); + hcchar.d32 = + dwc_read_reg32(&hcd->core_if->host_if->hc_regs[i]-> + hcchar); + hctsiz.d32 = + dwc_read_reg32(&hcd->core_if->host_if->hc_regs[i]-> + hctsiz); + hcint.d32 = + dwc_read_reg32(&hcd->core_if->host_if->hc_regs[i]-> + hcint); + hcintmsk.d32 = + dwc_read_reg32(&hcd->core_if->host_if->hc_regs[i]-> + hcintmsk); + DWC_PRINTF(" hfnum: 0x%08x\n", hfnum.d32); + DWC_PRINTF(" hcchar: 0x%08x\n", hcchar.d32); + DWC_PRINTF(" hctsiz: 0x%08x\n", hctsiz.d32); + DWC_PRINTF(" hcint: 0x%08x\n", hcint.d32); + DWC_PRINTF(" hcintmsk: 0x%08x\n", hcintmsk.d32); + } + if (hc->xfer_started && hc->qh) { + dwc_otg_qtd_t *qtd; + dwc_otg_hcd_urb_t *urb; + + DWC_CIRCLEQ_FOREACH(qtd, &hc->qh->qtd_list, qtd_list_entry) { + if(!qtd->in_process) + break; + + urb = qtd->urb; + DWC_PRINTF(" URB Info:\n"); + DWC_PRINTF(" qtd: %p, urb: %p\n", qtd, urb); + if (urb) { + DWC_PRINTF(" Dev: %d, EP: %d %s\n", + dwc_otg_hcd_get_dev_addr(&urb-> + pipe_info), + dwc_otg_hcd_get_ep_num(&urb-> + pipe_info), + dwc_otg_hcd_is_pipe_in(&urb-> + pipe_info) ? + "IN" : "OUT"); + DWC_PRINTF(" Max packet size: %d\n", + dwc_otg_hcd_get_mps(&urb-> + pipe_info)); + DWC_PRINTF(" transfer_buffer: %p\n", + urb->buf); + DWC_PRINTF(" transfer_dma: %p\n", + (void *)urb->dma); + DWC_PRINTF(" transfer_buffer_length: %d\n", + urb->length); + DWC_PRINTF(" actual_length: %d\n", + urb->actual_length); + } + } + } + } + DWC_PRINTF(" non_periodic_channels: %d\n", hcd->non_periodic_channels); + DWC_PRINTF(" periodic_channels: %d\n", hcd->periodic_channels); + DWC_PRINTF(" periodic_usecs: %d\n", hcd->periodic_usecs); + np_tx_status.d32 = + dwc_read_reg32(&hcd->core_if->core_global_regs->gnptxsts); + DWC_PRINTF(" NP Tx Req Queue Space Avail: %d\n", + np_tx_status.b.nptxqspcavail); + DWC_PRINTF(" NP Tx FIFO Space Avail: %d\n", + np_tx_status.b.nptxfspcavail); + p_tx_status.d32 = + dwc_read_reg32(&hcd->core_if->host_if->host_global_regs->hptxsts); + DWC_PRINTF(" P Tx Req Queue Space Avail: %d\n", + p_tx_status.b.ptxqspcavail); + DWC_PRINTF(" P Tx FIFO Space Avail: %d\n", p_tx_status.b.ptxfspcavail); + dwc_otg_hcd_dump_frrem(hcd); + dwc_otg_dump_global_registers(hcd->core_if); + dwc_otg_dump_host_registers(hcd->core_if); + DWC_PRINTF + ("************************************************************\n"); + DWC_PRINTF("\n"); +#endif +} + +#ifdef DEBUG +void dwc_print_setup_data(uint8_t * setup) +{ + int i; + if (CHK_DEBUG_LEVEL(DBG_HCD)) { + DWC_PRINTF("Setup Data = MSB "); + for (i = 7; i >= 0; i--) + DWC_PRINTF("%02x ", setup[i]); + DWC_PRINTF("\n"); + DWC_PRINTF(" bmRequestType Tranfer = %s\n", + (setup[0] & 0x80) ? "Device-to-Host" : + "Host-to-Device"); + DWC_PRINTF(" bmRequestType Type = "); + switch ((setup[0] & 0x60) >> 5) { + case 0: + DWC_PRINTF("Standard\n"); + break; + case 1: + DWC_PRINTF("Class\n"); + break; + case 2: + DWC_PRINTF("Vendor\n"); + break; + case 3: + DWC_PRINTF("Reserved\n"); + break; + } + DWC_PRINTF(" bmRequestType Recipient = "); + switch (setup[0] & 0x1f) { + case 0: + DWC_PRINTF("Device\n"); + break; + case 1: + DWC_PRINTF("Interface\n"); + break; + case 2: + DWC_PRINTF("Endpoint\n"); + break; + case 3: + DWC_PRINTF("Other\n"); + break; + default: + DWC_PRINTF("Reserved\n"); + break; + } + DWC_PRINTF(" bRequest = 0x%0x\n", setup[1]); + DWC_PRINTF(" wValue = 0x%0x\n", *((uint16_t *) & setup[2])); + DWC_PRINTF(" wIndex = 0x%0x\n", *((uint16_t *) & setup[4])); + DWC_PRINTF(" wLength = 0x%0x\n\n", *((uint16_t *) & setup[6])); + } +} +#endif + +void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd) +{ +#if 0 + DWC_PRINTF("Frame remaining at SOF:\n"); + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n", + hcd->frrem_samples, hcd->frrem_accum, + (hcd->frrem_samples > 0) ? + hcd->frrem_accum / hcd->frrem_samples : 0); + + DWC_PRINTF("\n"); + DWC_PRINTF("Frame remaining at start_transfer (uframe 7):\n"); + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n", + hcd->core_if->hfnum_7_samples, + hcd->core_if->hfnum_7_frrem_accum, + (hcd->core_if->hfnum_7_samples > + 0) ? hcd->core_if->hfnum_7_frrem_accum / + hcd->core_if->hfnum_7_samples : 0); + DWC_PRINTF("Frame remaining at start_transfer (uframe 0):\n"); + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n", + hcd->core_if->hfnum_0_samples, + hcd->core_if->hfnum_0_frrem_accum, + (hcd->core_if->hfnum_0_samples > + 0) ? hcd->core_if->hfnum_0_frrem_accum / + hcd->core_if->hfnum_0_samples : 0); + DWC_PRINTF("Frame remaining at start_transfer (uframe 1-6):\n"); + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n", + hcd->core_if->hfnum_other_samples, + hcd->core_if->hfnum_other_frrem_accum, + (hcd->core_if->hfnum_other_samples > + 0) ? hcd->core_if->hfnum_other_frrem_accum / + hcd->core_if->hfnum_other_samples : 0); + + DWC_PRINTF("\n"); + DWC_PRINTF("Frame remaining at sample point A (uframe 7):\n"); + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n", + hcd->hfnum_7_samples_a, hcd->hfnum_7_frrem_accum_a, + (hcd->hfnum_7_samples_a > 0) ? + hcd->hfnum_7_frrem_accum_a / hcd->hfnum_7_samples_a : 0); + DWC_PRINTF("Frame remaining at sample point A (uframe 0):\n"); + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n", + hcd->hfnum_0_samples_a, hcd->hfnum_0_frrem_accum_a, + (hcd->hfnum_0_samples_a > 0) ? + hcd->hfnum_0_frrem_accum_a / hcd->hfnum_0_samples_a : 0); + DWC_PRINTF("Frame remaining at sample point A (uframe 1-6):\n"); + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n", + hcd->hfnum_other_samples_a, hcd->hfnum_other_frrem_accum_a, + (hcd->hfnum_other_samples_a > 0) ? + hcd->hfnum_other_frrem_accum_a / + hcd->hfnum_other_samples_a : 0); + + DWC_PRINTF("\n"); + DWC_PRINTF("Frame remaining at sample point B (uframe 7):\n"); + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n", + hcd->hfnum_7_samples_b, hcd->hfnum_7_frrem_accum_b, + (hcd->hfnum_7_samples_b > 0) ? + hcd->hfnum_7_frrem_accum_b / hcd->hfnum_7_samples_b : 0); + DWC_PRINTF("Frame remaining at sample point B (uframe 0):\n"); + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n", + hcd->hfnum_0_samples_b, hcd->hfnum_0_frrem_accum_b, + (hcd->hfnum_0_samples_b > 0) ? + hcd->hfnum_0_frrem_accum_b / hcd->hfnum_0_samples_b : 0); + DWC_PRINTF("Frame remaining at sample point B (uframe 1-6):\n"); + DWC_PRINTF(" samples %u, accum %llu, avg %llu\n", + hcd->hfnum_other_samples_b, hcd->hfnum_other_frrem_accum_b, + (hcd->hfnum_other_samples_b > 0) ? + hcd->hfnum_other_frrem_accum_b / + hcd->hfnum_other_samples_b : 0); +#endif +} + +#endif /* DWC_DEVICE_ONLY */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h new file mode 100644 index 000000000000..9459c4ccff95 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h @@ -0,0 +1,804 @@ +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.h $ + * $Revision: #52 $ + * $Date: 2009/04/21 $ + * $Change: 1237472 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ +#ifndef DWC_DEVICE_ONLY +#ifndef __DWC_HCD_H__ +#define __DWC_HCD_H__ + +#include +#include "dwc_otg_hcd_if.h" +#include "dwc_otg_core_if.h" +#include "dwc_list.h" +#include "dwc_otg_cil.h" + +/** + * @file + * + * This file contains the structures, constants, and interfaces for + * the Host Contoller Driver (HCD). + * + * The Host Controller Driver (HCD) is responsible for translating requests + * from the USB Driver into the appropriate actions on the DWC_otg controller. + * It isolates the USBD from the specifics of the controller by providing an + * API to the USBD. + */ + +struct dwc_otg_hcd_pipe_info { + uint8_t dev_addr; + uint8_t ep_num; + uint8_t pipe_type; + uint8_t pipe_dir; + uint16_t mps; +}; + +struct dwc_otg_hcd_iso_packet_desc { + uint32_t offset; + uint32_t length; + uint32_t actual_length; + uint32_t status; +}; + +struct dwc_otg_qtd; + +struct dwc_otg_hcd_urb { + void *priv; + struct dwc_otg_qtd *qtd; + void *buf; + dwc_dma_t dma; + void *setup_packet; + dwc_dma_t setup_dma; + uint32_t length; + uint32_t actual_length; + uint32_t status; + uint32_t error_count; + uint32_t packet_count; + uint32_t flags; + uint16_t interval; + struct dwc_otg_hcd_pipe_info pipe_info; + struct dwc_otg_hcd_iso_packet_desc iso_descs[0]; +}; + +static inline uint8_t dwc_otg_hcd_get_ep_num(struct dwc_otg_hcd_pipe_info *pipe) +{ + return pipe->ep_num; +} + +static inline uint8_t dwc_otg_hcd_get_pipe_type(struct dwc_otg_hcd_pipe_info + *pipe) +{ + return pipe->pipe_type; +} + +static inline uint16_t dwc_otg_hcd_get_mps(struct dwc_otg_hcd_pipe_info *pipe) +{ + return pipe->mps; +} + +static inline uint8_t dwc_otg_hcd_get_dev_addr(struct dwc_otg_hcd_pipe_info + *pipe) +{ + return pipe->dev_addr; +} + +static inline uint8_t dwc_otg_hcd_is_pipe_isoc(struct dwc_otg_hcd_pipe_info + *pipe) +{ + return (pipe->pipe_type == UE_ISOCHRONOUS); +} + +static inline uint8_t dwc_otg_hcd_is_pipe_int(struct dwc_otg_hcd_pipe_info + *pipe) +{ + return (pipe->pipe_type == UE_INTERRUPT); +} + +static inline uint8_t dwc_otg_hcd_is_pipe_bulk(struct dwc_otg_hcd_pipe_info + *pipe) +{ + return (pipe->pipe_type == UE_BULK); +} + +static inline uint8_t dwc_otg_hcd_is_pipe_control(struct dwc_otg_hcd_pipe_info + *pipe) +{ + return (pipe->pipe_type == UE_CONTROL); +} + +static inline uint8_t dwc_otg_hcd_is_pipe_in(struct dwc_otg_hcd_pipe_info *pipe) +{ + return (pipe->pipe_dir == UE_DIR_IN); +} + +static inline uint8_t dwc_otg_hcd_is_pipe_out(struct dwc_otg_hcd_pipe_info + *pipe) +{ + return (!dwc_otg_hcd_is_pipe_in(pipe)); +} + +static inline void dwc_otg_hcd_fill_pipe(struct dwc_otg_hcd_pipe_info *pipe, + uint8_t devaddr, uint8_t ep_num, + uint8_t pipe_type, uint8_t pipe_dir, + uint16_t mps) +{ + pipe->dev_addr = devaddr; + pipe->ep_num = ep_num; + pipe->pipe_type = pipe_type; + pipe->pipe_dir = pipe_dir; + pipe->mps = mps; +} + +/** + * Phases for control transfers. + */ +typedef enum dwc_otg_control_phase { + DWC_OTG_CONTROL_SETUP, + DWC_OTG_CONTROL_DATA, + DWC_OTG_CONTROL_STATUS +} dwc_otg_control_phase_e; + +/** Transaction types. */ +typedef enum dwc_otg_transaction_type { + DWC_OTG_TRANSACTION_NONE, + DWC_OTG_TRANSACTION_PERIODIC, + DWC_OTG_TRANSACTION_NON_PERIODIC, + DWC_OTG_TRANSACTION_ALL +} dwc_otg_transaction_type_e; + +struct dwc_otg_qh; + +/** + * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control, + * interrupt, or isochronous transfer. A single QTD is created for each URB + * (of one of these types) submitted to the HCD. The transfer associated with + * a QTD may require one or multiple transactions. + * + * A QTD is linked to a Queue Head, which is entered in either the + * non-periodic or periodic schedule for execution. When a QTD is chosen for + * execution, some or all of its transactions may be executed. After + * execution, the state of the QTD is updated. The QTD may be retired if all + * its transactions are complete or if an error occurred. Otherwise, it + * remains in the schedule so more transactions can be executed later. + */ +typedef struct dwc_otg_qtd { + /** + * Determines the PID of the next data packet for the data phase of + * control transfers. Ignored for other transfer types.
+ * One of the following values: + * - DWC_OTG_HC_PID_DATA0 + * - DWC_OTG_HC_PID_DATA1 + */ + uint8_t data_toggle; + + /** Current phase for control transfers (Setup, Data, or Status). */ + dwc_otg_control_phase_e control_phase; + + /** Keep track of the current split type + * for FS/LS endpoints on a HS Hub */ + uint8_t complete_split; + + /** How many bytes transferred during SSPLIT OUT */ + uint32_t ssplit_out_xfer_count; + + /** + * Holds the number of bus errors that have occurred for a transaction + * within this transfer. + */ + uint8_t error_count; + + /** + * Index of the next frame descriptor for an isochronous transfer. A + * frame descriptor describes the buffer position and length of the + * data to be transferred in the next scheduled (micro)frame of an + * isochronous transfer. It also holds status for that transaction. + * The frame index starts at 0. + */ + uint16_t isoc_frame_index; + + /** Position of the ISOC split on full/low speed */ + uint8_t isoc_split_pos; + + /** Position of the ISOC split in the buffer for the current frame */ + uint16_t isoc_split_offset; + + /** URB for this transfer */ + struct dwc_otg_hcd_urb *urb; + + struct dwc_otg_qh *qh; + + /** This list of QTDs */ + DWC_CIRCLEQ_ENTRY(dwc_otg_qtd) qtd_list_entry; + + /** Indicates if this QTD is currently processed by HW. */ + uint8_t in_process; + + /** Number of DMA descriptors for this QTD */ + uint8_t n_desc; + + /** + * Last activated frame(packet) index. + * Used in Descriptor DMA mode only. + */ + uint16_t isoc_frame_index_last; + +} dwc_otg_qtd_t; + +DWC_CIRCLEQ_HEAD(dwc_otg_qtd_list, dwc_otg_qtd); + +/** + * A Queue Head (QH) holds the static characteristics of an endpoint and + * maintains a list of transfers (QTDs) for that endpoint. A QH structure may + * be entered in either the non-periodic or periodic schedule. + */ +typedef struct dwc_otg_qh { + /** + * Endpoint type. + * One of the following values: + * - UE_CONTROL + * - UE_BULK + * - UE_INTERRUPT + * - UE_ISOCHRONOUS + */ + uint8_t ep_type; + uint8_t ep_is_in; + + /** wMaxPacketSize Field of Endpoint Descriptor. */ + uint16_t maxp; + + /** + * Device speed. + * One of the following values: + * - DWC_OTG_EP_SPEED_LOW + * - DWC_OTG_EP_SPEED_FULL + * - DWC_OTG_EP_SPEED_HIGH + */ + uint8_t dev_speed; + + /** + * Determines the PID of the next data packet for non-control + * transfers. Ignored for control transfers.
+ * One of the following values: + * - DWC_OTG_HC_PID_DATA0 + * - DWC_OTG_HC_PID_DATA1 + */ + uint8_t data_toggle; + + /** Ping state if 1. */ + uint8_t ping_state; + + /** + * List of QTDs for this QH. + */ + struct dwc_otg_qtd_list qtd_list; + + /** Host channel currently processing transfers for this QH. */ + struct dwc_hc *channel; + + /** Full/low speed endpoint on high-speed hub requires split. */ + uint8_t do_split; + + /** @name Periodic schedule information */ + /** @{ */ + + /** Bandwidth in microseconds per (micro)frame. */ + uint16_t usecs; + + /** Interval between transfers in (micro)frames. */ + uint16_t interval; + + /** + * (micro)frame to initialize a periodic transfer. The transfer + * executes in the following (micro)frame. + */ + uint16_t sched_frame; + + /** (micro)frame at which last start split was initialized. */ + uint16_t start_split_frame; + + /** @} */ + + /** + * Used instead of original buffer if + * it(physical address) is not dword-aligned. + */ + uint8_t *dw_align_buf; + dwc_dma_t dw_align_buf_dma; + + /** Entry for QH in either the periodic or non-periodic schedule. */ + dwc_list_link_t qh_list_entry; + + /** @name Descriptor DMA support */ + /** @{ */ + + /** Descriptor List. */ + dwc_otg_host_dma_desc_t *desc_list; + + /** Descriptor List physical address. */ + dwc_dma_t desc_list_dma; + + /** + * Xfer Bytes array. + * Each element corresponds to a descriptor and indicates + * original XferSize size value for the descriptor. + */ + uint32_t *n_bytes; + + /** Actual number of transfer descriptors in a list. */ + uint16_t ntd; + + /** First activated isochronous transfer descriptor index. */ + uint8_t td_first; + /** Last activated isochronous transfer descriptor index. */ + uint8_t td_last; + + /** @} */ + +} dwc_otg_qh_t; + +DWC_CIRCLEQ_HEAD(hc_list, dwc_hc); + +#ifdef HW2937_WORKAROUND + +typedef enum { + HW2937_XFER_MODE_IDLE, + HW2937_XFER_MODE_IN, + HW2937_XFER_MODE_OUT, + HW2937_XFER_MODE_PAUSEIN /* Transitioning from IN to IDLE */ +} hw2937_xfer_mode_t; +#endif + +/** + * This structure holds the state of the HCD, including the non-periodic and + * periodic schedules. + */ +struct dwc_otg_hcd { + /** DWC OTG Core Interface Layer */ + dwc_otg_core_if_t *core_if; + + /** Function HCD driver callbacks */ + struct dwc_otg_hcd_function_ops *fops; + + /** Internal DWC HCD Flags */ + volatile union dwc_otg_hcd_internal_flags { + uint32_t d32; + struct { + unsigned port_connect_status_change:1; + unsigned port_connect_status:1; + unsigned port_reset_change:1; + unsigned port_enable_change:1; + unsigned port_suspend_change:1; + unsigned port_over_current_change:1; + unsigned port_l1_change:1; + unsigned reserved:26; + } b; + } flags; + + /** + * Inactive items in the non-periodic schedule. This is a list of + * Queue Heads. Transfers associated with these Queue Heads are not + * currently assigned to a host channel. + */ + dwc_list_link_t non_periodic_sched_inactive; + + /** + * Active items in the non-periodic schedule. This is a list of + * Queue Heads. Transfers associated with these Queue Heads are + * currently assigned to a host channel. + */ + dwc_list_link_t non_periodic_sched_active; + + /** + * Pointer to the next Queue Head to process in the active + * non-periodic schedule. + */ + dwc_list_link_t *non_periodic_qh_ptr; + + /** + * Inactive items in the periodic schedule. This is a list of QHs for + * periodic transfers that are _not_ scheduled for the next frame. + * Each QH in the list has an interval counter that determines when it + * needs to be scheduled for execution. This scheduling mechanism + * allows only a simple calculation for periodic bandwidth used (i.e. + * must assume that all periodic transfers may need to execute in the + * same frame). However, it greatly simplifies scheduling and should + * be sufficient for the vast majority of OTG hosts, which need to + * connect to a small number of peripherals at one time. + * + * Items move from this list to periodic_sched_ready when the QH + * interval counter is 0 at SOF. + */ + dwc_list_link_t periodic_sched_inactive; + + /** + * List of periodic QHs that are ready for execution in the next + * frame, but have not yet been assigned to host channels. + * + * Items move from this list to periodic_sched_assigned as host + * channels become available during the current frame. + */ + dwc_list_link_t periodic_sched_ready; + + /** + * List of periodic QHs to be executed in the next frame that are + * assigned to host channels. + * + * Items move from this list to periodic_sched_queued as the + * transactions for the QH are queued to the DWC_otg controller. + */ + dwc_list_link_t periodic_sched_assigned; + + /** + * List of periodic QHs that have been queued for execution. + * + * Items move from this list to either periodic_sched_inactive or + * periodic_sched_ready when the channel associated with the transfer + * is released. If the interval for the QH is 1, the item moves to + * periodic_sched_ready because it must be rescheduled for the next + * frame. Otherwise, the item moves to periodic_sched_inactive. + */ + dwc_list_link_t periodic_sched_queued; + + /** + * Total bandwidth claimed so far for periodic transfers. This value + * is in microseconds per (micro)frame. The assumption is that all + * periodic transfers may occur in the same (micro)frame. + */ + uint16_t periodic_usecs; + + /** + * Frame number read from the core at SOF. The value ranges from 0 to + * DWC_HFNUM_MAX_FRNUM. + */ + uint16_t frame_number; + + /** + * Free host channels in the controller. This is a list of + * dwc_hc_t items. + */ + struct hc_list free_hc_list; + /** + * Number of host channels assigned to periodic transfers. Currently + * assuming that there is a dedicated host channel for each periodic + * transaction and at least one host channel available for + * non-periodic transactions. + */ + int periodic_channels; + + /** + * Number of host channels assigned to non-periodic transfers. + */ + int non_periodic_channels; + + /** + * Array of pointers to the host channel descriptors. Allows accessing + * a host channel descriptor given the host channel number. This is + * useful in interrupt handlers. + */ + struct dwc_hc *hc_ptr_array[MAX_EPS_CHANNELS]; + + /** + * Buffer to use for any data received during the status phase of a + * control transfer. Normally no data is transferred during the status + * phase. This buffer is used as a bit bucket. + */ + uint8_t *status_buf; + + /** + * DMA address for status_buf. + */ + dma_addr_t status_buf_dma; +#define DWC_OTG_HCD_STATUS_BUF_SIZE 64 + + /** + * Connection timer. An OTG host must display a message if the device + * does not connect. Started when the VBus power is turned on via + * sysfs attribute "buspower". + */ + dwc_timer_t *conn_timer; + + /* Tasket to do a reset */ + dwc_tasklet_t *reset_tasklet; + + /* */ + dwc_spinlock_t *lock; + + /** + * Private data that could be used by OS wrapper. + */ + void *priv; + + uint8_t otg_port; + + /** Frame List */ + uint32_t *frame_list; + + /** Frame List DMA address */ + dma_addr_t frame_list_dma; + +#ifdef HW2937_WORKAROUND + /** Current transfer mode (IN, OUT, or IDLE) */ + hw2937_xfer_mode_t hw2937_xfer_mode; + + /** Mask of channels assigned to the current mode */ + uint32_t hw2937_assigned_channels; +#endif + +#ifdef DEBUG + uint32_t frrem_samples; + uint64_t frrem_accum; + + uint32_t hfnum_7_samples_a; + uint64_t hfnum_7_frrem_accum_a; + uint32_t hfnum_0_samples_a; + uint64_t hfnum_0_frrem_accum_a; + uint32_t hfnum_other_samples_a; + uint64_t hfnum_other_frrem_accum_a; + + uint32_t hfnum_7_samples_b; + uint64_t hfnum_7_frrem_accum_b; + uint32_t hfnum_0_samples_b; + uint64_t hfnum_0_frrem_accum_b; + uint32_t hfnum_other_samples_b; + uint64_t hfnum_other_frrem_accum_b; +#endif +}; + +/** @name Transaction Execution Functions */ +/** @{ */ +extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t + * hcd); +extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd, + dwc_otg_transaction_type_e tr_type); + +/** @} */ + +/** @name Interrupt Handler Functions */ +/** @{ */ +extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd); +extern int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * dwc_otg_hcd); +extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t * + dwc_otg_hcd); +extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t * + dwc_otg_hcd); +extern int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t * + dwc_otg_hcd); +extern int32_t dwc_otg_hcd_handle_incomplete_periodic_intr(dwc_otg_hcd_t * + dwc_otg_hcd); +extern int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd); +extern int32_t dwc_otg_hcd_handle_conn_id_status_change_intr(dwc_otg_hcd_t * + dwc_otg_hcd); +extern int32_t dwc_otg_hcd_handle_disconnect_intr(dwc_otg_hcd_t * dwc_otg_hcd); +extern int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd); +extern int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, + uint32_t num); +extern int32_t dwc_otg_hcd_handle_session_req_intr(dwc_otg_hcd_t * dwc_otg_hcd); +extern int32_t dwc_otg_hcd_handle_wakeup_detected_intr(dwc_otg_hcd_t * + dwc_otg_hcd); +/** @} */ + +/** @name Schedule Queue Functions */ +/** @{ */ + +/* Implemented in dwc_otg_hcd_queue.c */ +extern dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd, + dwc_otg_hcd_urb_t * urb); +extern void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh); +extern int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh); +extern void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh); +extern void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, + int sched_csplit); + +/** Remove and free a QH */ +static inline void dwc_otg_hcd_qh_remove_and_free(dwc_otg_hcd_t * hcd, + dwc_otg_qh_t * qh) +{ + dwc_otg_hcd_qh_remove(hcd, qh); + dwc_otg_hcd_qh_free(hcd, qh); +} + +/** Allocates memory for a QH structure. + * @return Returns the memory allocate or NULL on error. */ +static inline dwc_otg_qh_t *dwc_otg_hcd_qh_alloc(void) +{ + return (dwc_otg_qh_t *) dwc_alloc(sizeof(dwc_otg_qh_t)); +} + +extern dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb); +extern void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb); +extern int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, dwc_otg_hcd_t * dwc_otg_hcd, + dwc_otg_qh_t ** qh); + +/** Allocates memory for a QTD structure. + * @return Returns the memory allocate or NULL on error. */ +static inline dwc_otg_qtd_t *dwc_otg_hcd_qtd_alloc(void) +{ + return (dwc_otg_qtd_t *) dwc_alloc(sizeof(dwc_otg_qtd_t)); +} + +/** Frees the memory for a QTD structure. QTD should already be removed from + * list. + * @param qtd QTD to free.*/ +static inline void dwc_otg_hcd_qtd_free(dwc_otg_qtd_t * qtd) +{ + dwc_free(qtd); +} + +/** Removes a QTD from list. + * @param hcd HCD instance. + * @param qtd QTD to remove from list. + * @param qh QTD belongs to. + */ +static inline void dwc_otg_hcd_qtd_remove(dwc_otg_hcd_t * hcd, + dwc_otg_qtd_t * qtd, + dwc_otg_qh_t * qh) +{ + uint64_t flags; + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); + DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry); + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); +} + +/** Remove and free a QTD */ +static inline void dwc_otg_hcd_qtd_remove_and_free(dwc_otg_hcd_t * hcd, + dwc_otg_qtd_t * qtd, + dwc_otg_qh_t * qh) +{ + dwc_otg_hcd_qtd_remove(hcd, qtd, qh); + dwc_otg_hcd_qtd_free(qtd); +} + +/** @} */ + +/** @name Descriptor DMA Supporting Functions */ +/** @{ */ + +extern void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh); +extern void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_halt_status_e halt_status); + +extern int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh); +extern void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh); + +/** @} */ + +/** @name Internal Functions */ +/** @{ */ +dwc_otg_qh_t *dwc_urb_to_qh(dwc_otg_hcd_urb_t * urb); +/** @} */ + +#ifdef CONFIG_USB_DWC_OTG_LPM +extern int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd, + uint8_t devaddr); +extern void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd); +#endif + +/** Gets the QH that contains the list_head */ +#define dwc_list_to_qh(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qh_t, qh_list_entry) + +/** Gets the QTD that contains the list_head */ +#define dwc_list_to_qtd(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qtd_t, qtd_list_entry) + +/** Check if QH is non-periodic */ +#define dwc_qh_is_non_per(_qh_ptr_) ((_qh_ptr_->ep_type == UE_BULK) || \ + (_qh_ptr_->ep_type == UE_CONTROL)) + +/** High bandwidth multiplier as encoded in highspeed endpoint descriptors */ +#define dwc_hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) + +/** Packet size for any kind of endpoint descriptor */ +#define dwc_max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff) + +/** + * Returns true if _frame1 is less than or equal to _frame2. The comparison is + * done modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the + * frame number when the max frame number is reached. + */ +static inline int dwc_frame_num_le(uint16_t frame1, uint16_t frame2) +{ + return ((frame2 - frame1) & DWC_HFNUM_MAX_FRNUM) <= + (DWC_HFNUM_MAX_FRNUM >> 1); +} + +/** + * Returns true if _frame1 is greater than _frame2. The comparison is done + * modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the frame + * number when the max frame number is reached. + */ +static inline int dwc_frame_num_gt(uint16_t frame1, uint16_t frame2) +{ + return (frame1 != frame2) && + (((frame1 - frame2) & DWC_HFNUM_MAX_FRNUM) < + (DWC_HFNUM_MAX_FRNUM >> 1)); +} + +/** + * Increments _frame by the amount specified by _inc. The addition is done + * modulo DWC_HFNUM_MAX_FRNUM. Returns the incremented value. + */ +static inline uint16_t dwc_frame_num_inc(uint16_t frame, uint16_t inc) +{ + return (frame + inc) & DWC_HFNUM_MAX_FRNUM; +} + +static inline uint16_t dwc_full_frame_num(uint16_t frame) +{ + return (frame & DWC_HFNUM_MAX_FRNUM) >> 3; +} + +static inline uint16_t dwc_micro_frame_num(uint16_t frame) +{ + return frame & 0x7; +} + +void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_qtd_t * qtd); + +#ifdef DEBUG +/** + * Macro to sample the remaining PHY clocks left in the current frame. This + * may be used during debugging to determine the average time it takes to + * execute sections of code. There are two possible sample points, "a" and + * "b", so the _letter argument must be one of these values. + * + * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For + * example, "cat /sys/devices/lm0/hcd_frrem". + */ +#define dwc_sample_frrem(_hcd, _qh, _letter) \ +{ \ + hfnum_data_t hfnum; \ + dwc_otg_qtd_t *qtd; \ + qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); \ + if (usb_pipeint(qtd->urb->pipe) && _qh->start_split_frame != 0 && !qtd->complete_split) { \ + hfnum.d32 = dwc_read_reg32(&_hcd->core_if->host_if->host_global_regs->hfnum); \ + switch (hfnum.b.frnum & 0x7) { \ + case 7: \ + _hcd->hfnum_7_samples_##_letter++; \ + _hcd->hfnum_7_frrem_accum_##_letter += hfnum.b.frrem; \ + break; \ + case 0: \ + _hcd->hfnum_0_samples_##_letter++; \ + _hcd->hfnum_0_frrem_accum_##_letter += hfnum.b.frrem; \ + break; \ + default: \ + _hcd->hfnum_other_samples_##_letter++; \ + _hcd->hfnum_other_frrem_accum_##_letter += hfnum.b.frrem; \ + break; \ + } \ + } \ +} +#else +#define dwc_sample_frrem(_hcd, _qh, _letter) +#endif +#endif +#endif /* DWC_DEVICE_ONLY */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c new file mode 100644 index 000000000000..21d1ab13a126 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c @@ -0,0 +1,1106 @@ +/*========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_ddma.c $ + * $Revision: #2 $ + * $Date: 2009/04/21 $ + * $Change: 1237473 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ +#ifndef DWC_DEVICE_ONLY + +/** @file + * This file contains Descriptor DMA support implementation for host mode. + */ + +#include "dwc_otg_hcd.h" +#include "dwc_otg_regs.h" + + +static inline uint8_t frame_list_idx(uint16_t frame) +{ + return (frame & (MAX_FRLIST_EN_NUM - 1)); +} + +static inline uint16_t desclist_idx_inc(uint16_t idx, uint16_t inc, uint8_t speed) +{ + return (idx + inc) & + (((speed == DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC) - 1); +} + +static inline uint16_t desclist_idx_dec(uint16_t idx, uint16_t inc, uint8_t speed) +{ + return (idx - inc) & + (((speed == DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC) - 1); +} + +static inline uint16_t max_desc_num(dwc_otg_qh_t * qh) +{ + return (((qh->ep_type == UE_ISOCHRONOUS) && (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH)) + ? + MAX_DMA_DESC_NUM_HS_ISOC + : + MAX_DMA_DESC_NUM_GENERIC); +} +static inline uint16_t frame_incr_val(dwc_otg_qh_t * qh) +{ + return ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) + ? ((qh->interval + 8 - 1) / 8) + : + qh->interval); +} + +static int desc_list_alloc(dwc_otg_qh_t * qh) +{ + int retval = 0; + + qh->desc_list = (dwc_otg_host_dma_desc_t *) + dwc_dma_alloc(sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh), + &qh->desc_list_dma + ); + + if (!qh->desc_list) { + retval = -DWC_E_NO_MEMORY; + DWC_ERROR("%s: DMA descriptor list allocation failed\n", __func__); + + } + + dwc_memset(qh->desc_list, 0x00, sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh)); + + + qh->n_bytes = (uint32_t *) dwc_alloc(sizeof(uint32_t) * max_desc_num(qh)); + + if (!qh->n_bytes) { + retval = -DWC_E_NO_MEMORY; + DWC_ERROR("%s: Failed to allocate array for descriptors' size actual values\n", + __func__); + + } + return retval; + +} + +static void desc_list_free(dwc_otg_qh_t * qh) +{ + if(qh->desc_list) { + dwc_dma_free(max_desc_num(qh), qh->desc_list, qh->desc_list_dma); + qh->desc_list = NULL; + } + + if (qh->n_bytes) { + dwc_free(qh->n_bytes); + qh->n_bytes = NULL; + } +} + +static int frame_list_alloc(dwc_otg_hcd_t * hcd) +{ + int retval = 0; + if (hcd->frame_list) + return 0; + + hcd->frame_list = dwc_dma_alloc(4 * MAX_FRLIST_EN_NUM, + &hcd->frame_list_dma + ); + if (!hcd->frame_list) { + retval = -DWC_E_NO_MEMORY; + DWC_ERROR("%s: Frame List allocation failed\n", __func__); + } + + dwc_memset(hcd->frame_list, 0x00, 4 * MAX_FRLIST_EN_NUM); + + return retval; +} + +static void frame_list_free(dwc_otg_hcd_t * hcd) +{ + if (!hcd->frame_list) + return; + + dwc_dma_free(4 * MAX_FRLIST_EN_NUM, hcd->frame_list, hcd->frame_list_dma); + hcd->frame_list = NULL; +} + +static void per_sched_enable(dwc_otg_hcd_t * hcd, uint16_t fr_list_en) +{ + + hcfg_data_t hcfg; + + hcfg.d32 = dwc_read_reg32(&hcd->core_if->host_if->host_global_regs->hcfg); + + if (hcfg.b.perschedstat) { + /* already enabled*/ + return; + } + + dwc_write_reg32(&hcd->core_if->host_if->host_global_regs->hflbaddr, hcd->frame_list_dma); + + switch(fr_list_en) { + case 64: + hcfg.b.frlisten = 3; + break; + case 32: + hcfg.b.frlisten = 2; + break; + case 16: + hcfg.b.frlisten = 1; + case 8: + hcfg.b.frlisten = 0; + default: + break; + } + + hcfg.b.perschedena = 1; + + DWC_DEBUGPL(DBG_HCD, "Enabling Periodic schedule\n"); + dwc_write_reg32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32); + +} + +static void per_sched_disable(dwc_otg_hcd_t * hcd) +{ + hcfg_data_t hcfg; + + hcfg.d32 = dwc_read_reg32(&hcd->core_if->host_if->host_global_regs->hcfg); + + if (!hcfg.b.perschedstat) { + /* already disabled */ + return; + } + hcfg.b.perschedena = 0; + + DWC_DEBUGPL(DBG_HCD, "Disabling Periodic schedule\n"); + dwc_write_reg32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32); +} + +/* + * Activates/Deactivates FrameList entries for the channel + * based on endpoint servicing period. + */ +void update_frame_list(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t enable) +{ + uint16_t i, j, inc; + dwc_hc_t *hc = qh->channel; + + inc = frame_incr_val(qh); + + if (qh->ep_type == UE_ISOCHRONOUS) + i = frame_list_idx(qh->sched_frame); + else + i = 0; + + j = i; + do { + if (enable) + hcd->frame_list[j] |= (1 << hc->hc_num); + else + hcd->frame_list[j] &= ~(1 << hc->hc_num); + j = (j + inc) & (MAX_FRLIST_EN_NUM - 1); + } + while (j != i); + + if (!enable) + return; + + hc->schinfo = 0; + if (qh->channel->speed == DWC_OTG_EP_SPEED_HIGH) { + j = 1; + for (i = 0 ; i < 8 / qh->interval; i++) { + hc->schinfo |= j; + j = j << qh->interval; + } + } + else { + hc->schinfo = 0xff; + } +} +#if 1 +void dump_frame_list(dwc_otg_hcd_t * hcd) +{ + int i = 0; + DWC_PRINTF("--FRAME LIST (hex) --\n"); + for (i = 0; i < MAX_FRLIST_EN_NUM; i++) { + DWC_PRINTF("%x\t",hcd->frame_list[i]); + if (!(i % 8) && i) + DWC_PRINTF("\n"); + } + DWC_PRINTF("\n----\n"); + +} +#endif + +static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) +{ + dwc_hc_t *hc = qh->channel; + if (dwc_qh_is_non_per(qh)) { + hcd->non_periodic_channels--; + } + else { + update_frame_list(hcd, qh, 0); + } + /* + * The condition is added to prevent double cleanup try in case of device + * disconnect. See channel cleanup in dwc_otg_hcd_disconnect_cb(). + */ + if (hc->qh) { + dwc_otg_hc_cleanup(hcd->core_if, hc); + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry); + hc->qh = NULL; + } + + qh->channel = NULL; + qh->ntd = 0; + + if (qh->desc_list) { + dwc_memset(qh->desc_list, 0x00, + sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh)); + } +} + +/** + * Initializes a QH structure's Descriptor DMA related members. + * Allocates memory for descriptor list. + * On first periodic QH, allocates memory for FrameList + * and enables periodic scheduling. + * + * @param hcd The HCD state structure for the DWC OTG controller. + * @param qh The QH to init. + * + * @return 0 if successful, negative error code otherwise. + */ +int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) +{ + int retval = 0; + + if (qh->do_split) { + DWC_ERROR("SPLIT Transfers are not supported in Descriptor DMA.\n"); + return -1; + } + + retval = desc_list_alloc(qh); + + if ((retval == 0) && (qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)) { + if(!hcd->frame_list) { + retval = frame_list_alloc(hcd); + /* Enable periodic schedule on first periodic QH */ + if (retval == 0) + per_sched_enable(hcd, MAX_FRLIST_EN_NUM); + } + } + + qh->ntd = 0; + + return retval; +} + +/** + * Frees descriptor list memory associated with the QH. + * If QH is periodic and the last, frees FrameList memory + * and disables periodic scheduling. + * + * @param hcd The HCD state structure for the DWC OTG controller. + * @param qh The QH to init. + */ +void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) +{ + desc_list_free(qh); + + /* + * Channel still assigned due to some reasons. + * Seen on Isoc URB dequeue. Channel halted but no subsequent + * ChHalted interrupt to release the channel. Afterwards + * when it comes here from endpoint disable routine + * channel remains assigned. + */ + if (qh->channel) + release_channel_ddma(hcd, qh); + + if ((qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT) + && !hcd->periodic_channels && hcd->frame_list) { + + per_sched_disable(hcd); + frame_list_free(hcd); + } +} + +static uint8_t frame_to_desc_idx(dwc_otg_qh_t * qh, uint16_t frame_idx) +{ + if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) { + /* + * Descriptor set(8 descriptors) index + * which is 8-aligned. + */ + return (frame_idx & ((MAX_DMA_DESC_NUM_HS_ISOC / 8) - 1)) * 8; + } + else { + return (frame_idx & (MAX_DMA_DESC_NUM_GENERIC - 1)); + } +} + +/* + * Determine starting frame for Isochronous transfer. + * Few frames skipped to prevent race condition with HC. + */ +static uint8_t calc_starting_frame(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t* skip_frames) +{ + uint16_t frame = 0; + hcd->frame_number = dwc_otg_hcd_get_frame_number(hcd); + + /* sched_frame is always frame number(not uFrame) both in FS and HS !! */ + + /* + * skip_frames is used to limit activated descriptors number + * to avoid the situation when HC services the last activated + * descriptor firstly. + * Example for FS: + * Current frame is 1, scheduled frame is 3. Since HC always fetches the descriptor + * corresponding to curr_frame+1, the descriptor corresponding to frame 2 + * will be fetched. If the number of descriptors is max=64 (or greather) the list will + * be fully programmed with Active descriptors and it is possible case(rare) that the latest + * descriptor(considering rollback) corresponding to frame 2 will be serviced first. + * HS case is more probable because, in fact, up to 11 uframes(16 in the code) + * may be skipped. + */ + if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) { + /* + * Consider uframe counter also, to start xfer asap. + * If half of the frame elapsed skip 2 frames otherwise + * just 1 frame. + * Starting descriptor index must be 8-aligned, so + * if the current frame is near to complete the next one + * is skipped as well. + */ + + if (dwc_micro_frame_num(hcd->frame_number) >= 5) { + *skip_frames = 2 * 8; + frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames); + } + else { + *skip_frames = 1 * 8; + frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames); + } + + frame = dwc_full_frame_num(frame); + } else { + /* + * Two frames are skipped for FS - the current and the next. + * But for descriptor programming, 1 frame(descriptor) is enough, + * see example above. + */ + *skip_frames = 1; + frame = dwc_frame_num_inc(hcd->frame_number, 2); + } + + return frame; +} +/* + * Calculate initial descriptor index for isochronous transfer + * based on scheduled frame. + */ +static uint8_t recalc_initial_desc_idx(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) +{ + uint16_t frame = 0, fr_idx, fr_idx_tmp; + uint8_t skip_frames = 0 ; + /* + * With current ISOC processing algorithm the channel is being + * released when no more QTDs in the list(qh->ntd == 0). + * Thus this function is called only when qh->ntd == 0 and qh->channel == 0. + * + * So qh->channel != NULL branch is not used and just not removed from the + * source file. It is required for another possible approach which is, + * do not disable and release the channel when ISOC session completed, + * just move QH to inactive schedule until new QTD arrives. + * On new QTD, the QH moved back to 'ready' schedule, + * starting frame and therefore starting desc_index are recalculated. + * In this case channel is released only on ep_disable. + */ + + /* Calculate starting descriptor index. For INTERRUPT endpoint it is always 0. */ + if (qh->channel) { + frame = calc_starting_frame(hcd, qh, &skip_frames); + /* + * Calculate initial descriptor index based on FrameList current bitmap + * and servicing period. + */ + fr_idx_tmp = frame_list_idx(frame); + fr_idx = (MAX_FRLIST_EN_NUM + frame_list_idx(qh->sched_frame) - fr_idx_tmp) + % frame_incr_val(qh); + fr_idx = (fr_idx + fr_idx_tmp) % MAX_FRLIST_EN_NUM; + } + else { + qh->sched_frame = calc_starting_frame(hcd, qh, &skip_frames); + fr_idx = frame_list_idx(qh->sched_frame); + } + + qh->td_first = qh->td_last = frame_to_desc_idx(qh, fr_idx); + + return skip_frames; +} + +#define ISOC_URB_GIVEBACK_ASAP + +#define MAX_ISOC_XFER_SIZE_FS 1023 +#define MAX_ISOC_XFER_SIZE_HS 3072 +#define DESCNUM_THRESHOLD 4 + +static void init_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t skip_frames) +{ + struct dwc_otg_hcd_iso_packet_desc *frame_desc; + dwc_otg_qtd_t *qtd; + dwc_otg_host_dma_desc_t *dma_desc; + uint16_t idx, inc, n_desc, ntd_max, max_xfer_size; + + idx = qh->td_last; + inc = qh->interval; + n_desc = 0; + + ntd_max = (max_desc_num(qh) + qh->interval - 1) / qh->interval; + if (skip_frames && !qh->channel) + ntd_max = ntd_max - skip_frames / qh->interval; + + max_xfer_size = (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) ? MAX_ISOC_XFER_SIZE_HS + : MAX_ISOC_XFER_SIZE_FS; + + DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) { + while ((qh->ntd < ntd_max) && (qtd->isoc_frame_index_last < qtd->urb->packet_count)) { + + dma_desc = &qh->desc_list[idx]; + dwc_memset(dma_desc, 0x00, sizeof(dwc_otg_host_dma_desc_t)); + + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last]; + + if (frame_desc->length > max_xfer_size) + qh->n_bytes[idx] = max_xfer_size; + else + qh->n_bytes[idx] = frame_desc->length; + dma_desc->status.b_isoc.n_bytes = qh->n_bytes[idx]; + dma_desc->status.b_isoc.a = 1; + + dma_desc->buf = qtd->urb->dma + frame_desc->offset; + + qh->ntd++; + + qtd->isoc_frame_index_last++; + + #ifdef ISOC_URB_GIVEBACK_ASAP + /* + * Set IOC for each descriptor corresponding to the + * last frame of the URB. + */ + if (qtd->isoc_frame_index_last == qtd->urb->packet_count) + dma_desc->status.b_isoc.ioc = 1; + + #endif + idx = desclist_idx_inc(idx, inc, qh->dev_speed); + n_desc++; + + } + qtd->in_process = 1; + } + + qh->td_last = idx; + +#ifdef ISOC_URB_GIVEBACK_ASAP + /* Set IOC for the last descriptor if descriptor list is full */ + if (qh->ntd == ntd_max) { + idx = desclist_idx_dec(qh->td_last, inc, qh->dev_speed); + qh->desc_list[idx].status.b_isoc.ioc = 1; + } +#else + /* + * Set IOC bit only for one descriptor. + * Always try to be ahead of HW processing, + * i.e. on IOC generation driver activates next descriptors but + * core continues to process descriptors followed the one with IOC set. + */ + + if (n_desc > DESCNUM_THRESHOLD) { + /* + * Move IOC "up". Required even if there is only one QTD + * in the list, cause QTDs migth continue to be queued, + * but during the activation it was only one queued. + * Actually more than one QTD might be in the list if this function called + * from XferCompletion - QTDs was queued during HW processing of the previous + * descriptor chunk. + */ + idx = dwc_desclist_idx_dec(idx, inc * ((qh->ntd + 1) / 2), qh->dev_speed); + } + else { + /* + * Set the IOC for the latest descriptor + * if either number of descriptor is not greather than threshold + * or no more new descriptors activated. + */ + idx = dwc_desclist_idx_dec(qh->td_last, inc, qh->dev_speed); + } + + qh->desc_list[idx].status.b_isoc.ioc = 1; +#endif +} + + +static void init_non_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) +{ + + dwc_hc_t *hc; + dwc_otg_host_dma_desc_t *dma_desc; + dwc_otg_qtd_t *qtd; + int num_packets, len, n_desc = 0; + + hc = qh->channel; + + /* + * Start with hc->xfer_buff initialized in + * assign_and_init_hc(), then if SG transfer consists of multiple URBs, + * this pointer re-assigned to the buffer of the currently processed QTD. + * For non-SG request there is always one QTD active. + */ + + DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) { + + if (n_desc) { + /* SG request - more than 1 QTDs */ + hc->xfer_buff = (uint8_t *)qtd->urb->dma + qtd->urb->actual_length; + hc->xfer_len = qtd->urb->length - qtd->urb->actual_length; + } + + qtd->n_desc = 0; + + do { + dma_desc = &qh->desc_list[n_desc]; + len = hc->xfer_len; + + + if (len > MAX_DMA_DESC_SIZE) + len = MAX_DMA_DESC_SIZE - hc->max_packet + 1; + + if (hc->ep_is_in) { + if (len > 0) { + num_packets = (len + hc->max_packet - 1) / hc->max_packet; + } + else { + /* Need 1 packet for transfer length of 0. */ + num_packets = 1; + } + /* Always program an integral # of max packets for IN transfers. */ + len = num_packets * hc->max_packet; + } + + dma_desc->status.b.n_bytes = len; + + qh->n_bytes[n_desc] = len; + + + if ((qh->ep_type == UE_CONTROL) && (qtd->control_phase == DWC_OTG_CONTROL_SETUP)) + dma_desc->status.b.sup = 1; /* Setup Packet */ + + dma_desc->status.b.a = 1; /* Active descriptor */ + + dma_desc->buf = (uint32_t) hc->xfer_buff; + + /* + * Last descriptor(or single) of IN transfer + * with actual size less than MaxPacket. + */ + if (len > hc->xfer_len) { + hc->xfer_len = 0; + } + else { + hc->xfer_buff += len; + hc->xfer_len -= len; + } + + qtd->n_desc++; + n_desc++; + } + while ((hc->xfer_len > 0) && (n_desc != MAX_DMA_DESC_NUM_GENERIC)); + + + qtd->in_process = 1; + + if (n_desc == MAX_DMA_DESC_NUM_GENERIC) + break; + } + + if (n_desc) { + /* Request Transfer Complete interrupt for the last descriptor */ + qh->desc_list[n_desc-1].status.b.ioc = 1; + /* End of List indicator */ + qh->desc_list[n_desc-1].status.b.eol = 1; + + hc->ntd = n_desc; + } +} + +/** + * For Control and Bulk endpoints initializes descriptor list + * and starts the transfer. + * + * For Interrupt and Isochronous endpoints initializes descriptor list + * then updates FrameList, marking appropriate entries as active. + * In case of Isochronous, the starting descriptor index is calculated based + * on the scheduled frame, but only on the first transfer descriptor within a session. + * Then starts the transfer via enabling the channel. + * For Isochronous endpoint the channel is not halted on XferComplete + * interrupt so remains assigned to the endpoint(QH) until session is done. + * + * @param hcd The HCD state structure for the DWC OTG controller. + * @param qh The QH to init. + * + * @return 0 if successful, negative error code otherwise. + */ +void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) +{ + /* Channel is already assigned */ + dwc_hc_t *hc = qh->channel; + uint8_t skip_frames = 0; + + switch (hc->ep_type) { + case DWC_OTG_EP_TYPE_CONTROL: + case DWC_OTG_EP_TYPE_BULK: + init_non_isoc_dma_desc(hcd, qh); + + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc); + break; + case DWC_OTG_EP_TYPE_INTR: + init_non_isoc_dma_desc(hcd, qh); + + update_frame_list(hcd, qh, 1); + + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc); + break; + case DWC_OTG_EP_TYPE_ISOC: + + if(!qh->ntd) + skip_frames = recalc_initial_desc_idx(hcd, qh); + + init_isoc_dma_desc(hcd, qh, skip_frames); + + if (!hc->xfer_started) { + + update_frame_list(hcd, qh, 1); + + /* + * Always set to max, instead of actual size. + * Otherwise ntd will be changed with + * channel being enabled. Not recommended. + * + */ + hc->ntd = max_desc_num(qh); + /* Enable channel only once for ISOC */ + dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc); + } + + break; + default: + + break; + } +} + +static void complete_isoc_xfer_ddma(dwc_otg_hcd_t *hcd, + dwc_hc_t *hc, + dwc_otg_hc_regs_t *hc_regs, + dwc_otg_halt_status_e halt_status) +{ + struct dwc_otg_hcd_iso_packet_desc *frame_desc; + dwc_otg_qtd_t *qtd, *qtd_tmp; + dwc_otg_qh_t *qh; + dwc_otg_host_dma_desc_t *dma_desc; + uint16_t idx, remain; + uint8_t urb_compl; + + qh = hc->qh; + idx = qh->td_first; + + + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) { + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) + qtd->in_process = 0; + return; + } + else if ((halt_status == DWC_OTG_HC_XFER_AHB_ERR) || + (halt_status == DWC_OTG_HC_XFER_BABBLE_ERR)) { + /* + * Channel is halted in these error cases. + * Considered as serious issues. + * Complete all URBs marking all frames as failed, + * irrespective whether some of the descriptors(frames) succeeded or no. + * Pass error code to completion routine as well, to + * update urb->status, some of class drivers might use it to stop + * queing transfer requests. + */ + int err = (halt_status == DWC_OTG_HC_XFER_AHB_ERR) + ? (-DWC_E_IO) + : (-DWC_E_OVERFLOW); + + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) { + for(idx = 0; idx < qtd->urb->packet_count; idx++) { + frame_desc = &qtd->urb->iso_descs[idx]; + frame_desc->status = err; + } + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, err); + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh); + } + return; + } + + + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) { + + if (!qtd->in_process) + break; + + urb_compl = 0; + + do { + + dma_desc = &qh->desc_list[idx]; + + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; + remain = hc->ep_is_in ? dma_desc->status.b_isoc.n_bytes : 0; + + if (dma_desc->status.b_isoc.sts == DMA_DESC_STS_PKTERR) { + /* + * XactError or, unable to complete all the transactions + * in the scheduled micro-frame/frame, + * both indicated by DMA_DESC_STS_PKTERR. + */ + qtd->urb->error_count++; + frame_desc->actual_length = qh->n_bytes[idx] - remain; + frame_desc->status = -DWC_E_PROTOCOL; + } + else { + /* Success */ + + frame_desc->actual_length = qh->n_bytes[idx] - remain; + frame_desc->status = 0; + } + + if (++qtd->isoc_frame_index == qtd->urb->packet_count) { + /* + * urb->status is not used for isoc transfers here. + * The individual frame_desc status are used instead. + */ + + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0); + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh); + + /* + * This check is necessary because urb_dequeue can be called + * from urb complete callback(sound driver example). + * All pending URBs are dequeued there, so no need for + * further processing. + */ + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) { + return; + } + + urb_compl = 1; + + } + + qh->ntd--; + + /* Stop if IOC requested descriptor reached */ + if (dma_desc->status.b_isoc.ioc) { + idx = desclist_idx_inc(idx, qh->interval, hc->speed); + goto stop_scan; + } + + idx = desclist_idx_inc(idx, qh->interval, hc->speed); + + if (urb_compl) + break; + } + while(idx != qh->td_first); + } +stop_scan: + qh->td_first = idx; +} + +uint8_t update_non_isoc_urb_state_ddma(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_qtd_t * qtd, + dwc_otg_host_dma_desc_t * dma_desc, + dwc_otg_halt_status_e halt_status, + uint32_t n_bytes, + uint8_t *xfer_done) +{ + + uint16_t remain = hc->ep_is_in ? dma_desc->status.b.n_bytes : 0; + dwc_otg_hcd_urb_t *urb = qtd->urb; + + + if (halt_status == DWC_OTG_HC_XFER_AHB_ERR) { + urb->status = -DWC_E_IO; + return 1; + } + if (dma_desc->status.b.sts == DMA_DESC_STS_PKTERR) { + switch (halt_status) { + case DWC_OTG_HC_XFER_STALL: + urb->status = -DWC_E_PIPE; + break; + case DWC_OTG_HC_XFER_BABBLE_ERR: + urb->status = -DWC_E_OVERFLOW; + break; + case DWC_OTG_HC_XFER_XACT_ERR: + urb->status = -DWC_E_PROTOCOL; + break; + default: + DWC_ERROR("%s: Unhandled descriptor error status (%d)\n", __func__, + halt_status); + break; + } + return 1; + } + + if (dma_desc->status.b.a == 1) { + DWC_DEBUGPL(DBG_HCDV, "Active descriptor encountered on channel %d\n", hc->hc_num); + return 0; + } + + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL) { + if (qtd->control_phase == DWC_OTG_CONTROL_DATA) { + urb->actual_length += n_bytes - remain; + if (remain || urb->actual_length == urb->length) { + /* + * For Control Data stage do not set urb->status=0 to prevent + * URB callback. Set it when Status phase done. See below. + */ + *xfer_done = 1; + } + + } + else if (qtd->control_phase == DWC_OTG_CONTROL_STATUS) { + urb->status = 0; + *xfer_done = 1; + } + /* No handling for SETUP stage */ + + } + else { + /* BULK and INTR */ + urb->actual_length += n_bytes - remain; + if (remain || urb->actual_length == urb->length) { + urb->status = 0; + *xfer_done = 1; + } + } + + return 0; +} + +static void complete_non_isoc_xfer_ddma(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_halt_status_e halt_status) +{ + dwc_otg_hcd_urb_t *urb = NULL; + dwc_otg_qtd_t *qtd, *qtd_tmp; + dwc_otg_qh_t *qh; + dwc_otg_host_dma_desc_t *dma_desc; + uint32_t n_bytes, n_desc, i; + uint8_t failed = 0, xfer_done; + + n_desc = 0; + + qh = hc->qh; + + + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) { + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) { + qtd->in_process = 0; + } + return; + } + + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) { + + urb = qtd->urb; + + n_bytes = 0; + xfer_done = 0; + + for (i = 0; i < qtd->n_desc; i++) { + dma_desc = &qh->desc_list[n_desc]; + + n_bytes = qh->n_bytes[n_desc]; + + + failed = update_non_isoc_urb_state_ddma(hcd, hc, qtd, dma_desc, + halt_status, n_bytes, &xfer_done); + + if (failed || (xfer_done && (urb->status != -DWC_E_IN_PROGRESS))) { + + hcd->fops->complete(hcd, urb->priv, urb, urb->status); + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh); + + if (failed) + goto stop_scan; + } + else if (qh->ep_type == UE_CONTROL) { + if (qtd->control_phase == DWC_OTG_CONTROL_SETUP) { + if (urb->length > 0) { + qtd->control_phase = DWC_OTG_CONTROL_DATA; + } else { + qtd->control_phase = DWC_OTG_CONTROL_STATUS; + } + DWC_DEBUGPL(DBG_HCDV, " Control setup transaction done\n"); + } + else if(qtd->control_phase == DWC_OTG_CONTROL_DATA) { + if (xfer_done) { + qtd->control_phase = DWC_OTG_CONTROL_STATUS; + DWC_DEBUGPL(DBG_HCDV, " Control data transfer done\n"); + } else if (i+1 == qtd->n_desc){ + /* + * Last descriptor for Control data stage which is + * not completed yet. + */ + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); + } + } + } + + n_desc++; + } + + } + +stop_scan: + + if (qh->ep_type != UE_CONTROL) { + /* + * Resetting the data toggle for bulk + * and interrupt endpoints in case of stall. See handle_hc_stall_intr() + */ + if (halt_status == DWC_OTG_HC_XFER_STALL) { + qh->data_toggle = DWC_OTG_HC_PID_DATA0; + } + else { + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); + } + } + + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) { + hcint_data_t hcint; + hcint.d32 = dwc_read_reg32(&hc_regs->hcint); + if (hcint.b.nyet) { + /* + * Got a NYET on the last transaction of the transfer. It + * means that the endpoint should be in the PING state at the + * beginning of the next transfer. + */ + qh->ping_state = 1; + clear_hc_int(hc_regs, nyet); + } + + } + +} + +/** + * This function is called from interrupt handlers. + * Scans the descriptor list, updates URB's status and + * calls completion routine for the URB if it's done. + * Releases the channel to be used by other transfers. + * In case of Isochronous endpoint the channel is not halted until + * the end of the session, i.e. QTD list is empty. + * If periodic channel released the FrameList is updated accordingly. + * + * Calls transaction selection routines to activate pending transfers. + * + * @param hcd The HCD state structure for the DWC OTG controller. + * @param hc Host channel, the transfer is completed on. + * @param hc_regs Host channel registers. + * @param halt_status Reason the channel is being halted, + * or just XferComplete for isochronous transfer + */ +void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t *hcd, + dwc_hc_t *hc, + dwc_otg_hc_regs_t *hc_regs, + dwc_otg_halt_status_e halt_status) +{ + uint8_t continue_isoc_xfer = 0; + dwc_otg_transaction_type_e tr_type; + dwc_otg_qh_t *qh = hc->qh; + + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { + + complete_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status); + + /* Release the channel if halted or session completed */ + if (halt_status != DWC_OTG_HC_XFER_COMPLETE || + DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) { + + /* Halt the channel if session completed */ + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) { + dwc_otg_hc_halt(hcd->core_if, hc, halt_status); + } + + release_channel_ddma(hcd, qh); + dwc_otg_hcd_qh_remove(hcd, qh); + } + else { + /* Keep in assigned schedule to continue transfer */ + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned, + &qh->qh_list_entry); + continue_isoc_xfer = 1; + + } + /** @todo Consider the case when period exceeds FrameList size. + * Frame Rollover interrupt should be used. + */ + } + else { + /* Scan descriptor list to complete the URB(s), then release the channel */ + complete_non_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status); + + release_channel_ddma(hcd, qh); + + dwc_otg_hcd_qh_remove(hcd, qh); + + if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) { + /* Add back to inactive non-periodic schedule on normal completion */ + dwc_otg_hcd_qh_add(hcd, qh); + } + + + } + tr_type = dwc_otg_hcd_select_transactions(hcd); + if (tr_type != DWC_OTG_TRANSACTION_NONE || continue_isoc_xfer) { + if (continue_isoc_xfer) { + if (tr_type == DWC_OTG_TRANSACTION_NONE) { + tr_type = DWC_OTG_TRANSACTION_PERIODIC; + } else if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC) { + tr_type = DWC_OTG_TRANSACTION_ALL; + } + } + dwc_otg_hcd_queue_transactions(hcd, tr_type); + } +} + +#endif /* DWC_DEVICE_ONLY */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h b/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h new file mode 100644 index 000000000000..d5a903bae77e --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h @@ -0,0 +1,393 @@ +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_if.h $ + * $Revision: #6 $ + * $Date: 2009/04/21 $ + * $Change: 1237474 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ +#ifndef DWC_DEVICE_ONLY +#ifndef __DWC_HCD_IF_H__ +#define __DWC_HCD_IF_H__ + +#include "dwc_otg_core_if.h" + +/** @file + * This file defines DWC_OTG HCD Core API. + */ + +struct dwc_otg_hcd; +typedef struct dwc_otg_hcd dwc_otg_hcd_t; + +struct dwc_otg_hcd_urb; +typedef struct dwc_otg_hcd_urb dwc_otg_hcd_urb_t; + +/** @name HCD Function Driver Callbacks */ +/** @{ */ + +/** This function is called whenever core switches to host mode. */ +typedef int (*dwc_otg_hcd_start_cb_t) (dwc_otg_hcd_t * hcd); + +/** This function is called when device has been disconnected */ +typedef int (*dwc_otg_hcd_disconnect_cb_t) (dwc_otg_hcd_t * hcd); + +/** Wrapper provides this function to HCD to core, so it can get hub information to which device is connected */ +typedef int (*dwc_otg_hcd_hub_info_from_urb_cb_t) (dwc_otg_hcd_t * hcd, + void *urb_handle, + uint32_t * hub_addr, + uint32_t * port_addr); +/** Via this function HCD core gets device speed */ +typedef int (*dwc_otg_hcd_speed_from_urb_cb_t) (dwc_otg_hcd_t * hcd, + void *urb_handle); + +/** This function is called when urb is completed */ +typedef int (*dwc_otg_hcd_complete_urb_cb_t) (dwc_otg_hcd_t * hcd, + void *urb_handle, + dwc_otg_hcd_urb_t * dwc_otg_urb, + int32_t status); + +/** Via this function HCD core gets b_hnp_enable parameter */ +typedef int (*dwc_otg_hcd_get_b_hnp_enable) (dwc_otg_hcd_t * hcd); + +struct dwc_otg_hcd_function_ops { + dwc_otg_hcd_start_cb_t start; + dwc_otg_hcd_disconnect_cb_t disconnect; + dwc_otg_hcd_hub_info_from_urb_cb_t hub_info; + dwc_otg_hcd_speed_from_urb_cb_t speed; + dwc_otg_hcd_complete_urb_cb_t complete; + dwc_otg_hcd_get_b_hnp_enable get_b_hnp_enable; +}; +/** @} */ + +/** @name HCD Core API */ +/** @{ */ +/** This function allocates dwc_otg_hcd structure and returns pointer on it. */ +extern dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void); + +/** This function should be called to initiate HCD Core. + * + * @param hcd The HCD + * @param core_if The DWC_OTG Core + * + * Returns -DWC_E_NO_MEMORY if no enough memory. + * Returns 0 on success + */ +extern int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if); + +/** Frees HCD + * + * @param hcd The HCD + */ +extern void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd); + +/** This function should be called on every hardware interrupt. + * + * @param dwc_otg_hcd The HCD + * + * Returns non zero if interrupt is handled + * Return 0 if interrupt is not handled + */ +extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd); + +/** + * Returns private data set by + * dwc_otg_hcd_set_priv_data function. + * + * @param hcd The HCD + */ +extern void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd); + +/** + * Set private data. + * + * @param hcd The HCD + * @param priv_data pointer to be stored in private data + */ +extern void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data); + +/** + * This function initializes the HCD Core. + * + * @param hcd The HCD + * @param fops The Function Driver Operations data structure containing pointers to all callbacks. + * + * Returns -DWC_E_NO_DEVICE if Core is currently is in device mode. + * Returns 0 on success + */ +extern int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd, + struct dwc_otg_hcd_function_ops *fops); + +/** + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are + * stopped. + * + * @param hcd The HCD + */ +extern void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd); + +/** + * Handles hub class-specific requests. + * + * @param dwc_otg_hcd The HCD + * @param typeReq Request Type + * @param wValue wValue from control request + * @param wIndex wIndex from control request + * @param buf data buffer + * @param wLength data buffer length + * + * Returns -DWC_E_INVALID if invalid argument is passed + * Returns 0 on success + */ +extern int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd, + uint16_t typeReq, uint16_t wValue, + uint16_t wIndex, uint8_t * buf, + uint16_t wLength); + +/** + * Returns otg port number. + * + * @param hcd The HCD + */ +extern uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd); + +/** + * Returns 1 if currently core is acting as B host, and 0 otherwise. + * + * @param hcd The HCD + */ +extern uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd); + +/** + * Returns current frame number. + * + * @param hcd The HCD + */ +extern int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * hcd); + +/** + * Dumps hcd state. + * + * @param hcd The HCD + */ +extern void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd); + +/** + * Dump the average frame remaining at SOF. This can be used to + * determine average interrupt latency. Frame remaining is also shown for + * start transfer and two additional sample points. + * Currently this function is not implemented. + * + * @param hcd The HCD + */ +extern void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd); + +/** + * Sends LPM transaction to the local device. + * + * @param hcd The HCD + * @param devaddr Device Address + * @param hird Host initiated resume duration + * @param bRemoteWake Value of bRemoteWake field in LPM transaction + * + * Returns negative value if sending LPM transaction was not succeeded. + * Returns 0 on success. + */ +extern int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr, + uint8_t hird, uint8_t bRemoteWake); + +/* URB interface */ + +/** + * Allocates memory for dwc_otg_hcd_urb structure. + * Allocated memory should be freed by call dwc_free function. + * + * @param hcd The HCD + * @param iso_desc_count Count of ISOC descriptors + * @param atomic_alloc Specefies whether to perform atomic allocation. + */ +extern dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd, + int iso_desc_count, + int atomic_alloc); + +/** + * Set pipe information in URB. + * + * @param hcd_urb DWC_OTG URB + * @param devaddr Device Address + * @param ep_num Endpoint Number + * @param ep_type Endpoint Type + * @param ep_dir Endpoint Direction + * @param mps Max Packet Size + */ +extern void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * hcd_urb, + uint8_t devaddr, uint8_t ep_num, + uint8_t ep_type, uint8_t ep_dir, + uint16_t mps); + +/* Transfer flags */ +#define URB_GIVEBACK_ASAP 0x1 +#define URB_SEND_ZERO_PACKET 0x2 + +/** + * Sets dwc_otg_hcd_urb parameters. + * + * @param urb DWC_OTG URB allocated by dwc_otg_hcd_urb_alloc function. + * @param urb_handle Unique handle for request, this will be passed back + * to function driver in completion callback. + * @param buf The buffer for the data + * @param dma The DMA buffer for the data + * @param buflen Transfer length + * @param sp Buffer for setup data + * @param sp_dma DMA address of setup data buffer + * @param flags Transfer flags + * @param interval Polling interval for interrupt or isochronous transfers. + */ +extern void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * urb, + void *urb_handle, void *buf, + dwc_dma_t dma, uint32_t buflen, void *sp, + dwc_dma_t sp_dma, uint32_t flags, + uint16_t interval); + +/** Gets status from dwc_otg_hcd_urb + * + * @param dwc_otg_urb DWC_OTG URB + */ +extern uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb); + +/** Gets actual length from dwc_otg_hcd_urb + * + * @param dwc_otg_urb DWC_OTG URB + */ +extern uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t * + dwc_otg_urb); + +/** Gets error count from dwc_otg_hcd_urb. Only for ISOC URBs + * + * @param dwc_otg_urb DWC_OTG URB + */ +extern uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t * + dwc_otg_urb); + +/** Set ISOC descriptor offset and length + * + * @param dwc_otg_urb DWC_OTG URB + * @param desc_num ISOC descriptor number + * @param offset Offset from beginig of buffer. + * @param length Transaction length + */ +extern void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb, + int desc_num, uint32_t offset, + uint32_t length); + +/** Get status of ISOC descriptor, specified by desc_num + * + * @param dwc_otg_urb DWC_OTG URB + * @param desc_num ISOC descriptor number + */ +extern uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t * + dwc_otg_urb, int desc_num); + +/** Get actual length of ISOC descriptor, specified by desc_num + * + * @param dwc_otg_urb DWC_OTG URB + * @param desc_num ISOC descriptor number + */ +extern uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t * + dwc_otg_urb, + int desc_num); + +/** Queue URB. After transfer is completes, the complete callback will be called with the URB status + * + * @param dwc_otg_hcd The HCD + * @param dwc_otg_urb DWC_OTG URB + * @param ep_handle Out parameter for returning endpoint handle + * + * Returns -DWC_E_NO_DEVICE if no device is connected. + * Returns -DWC_E_NO_MEMORY if there is no enough memory. + * Returns 0 on success. + */ +extern int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * dwc_otg_hcd, + dwc_otg_hcd_urb_t * dwc_otg_urb, + void **ep_handle); + +/** De-queue the specified URB + * + * @param dwc_otg_hcd The HCD + * @param dwc_otg_urb DWC_OTG URB + */ +extern int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * dwc_otg_hcd, + dwc_otg_hcd_urb_t * dwc_otg_urb); + +/** Frees resources in the DWC_otg controller related to a given endpoint. + * Any URBs for the endpoint must already be dequeued. + * + * @param hcd The HCD + * @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function + * @param retry Number of retries if there are queued transfers. + * + * Returns -DWC_E_INVALID if invalid arguments are passed. + * Returns 0 on success + */ +extern int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle, + int retry); + +/** Returns 1 if status of specified port is changed and 0 otherwise. + * + * @param hcd The HCD + * @param port Port number + */ +extern int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port); + +/** Call this function to check if bandwidth was allocated for specified endpoint. + * Only for ISOC and INTERRUPT endpoints. + * + * @param hcd The HCD + * @param ep_handle Endpoint handle + */ +extern int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd, + void *ep_handle); + +/** Call this function to check if bandwidth was freed for specified endpoint. + * + * @param hcd The HCD + * @param ep_handle Endpoint handle + */ +extern int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle); + +/** Returns bandwidth allocated for specified endpoint in microseconds. + * Only for ISOC and INTERRUPT endpoints. + * + * @param hcd The HCD + * @param ep_handle Endpoint handle + */ +extern uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd, + void *ep_handle); + +/** @} */ + +#endif /* __DWC_HCD_IF_H__ */ +#endif /* DWC_DEVICE_ONLY */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c new file mode 100644 index 000000000000..6e4bc60b328a --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c @@ -0,0 +1,2065 @@ +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_intr.c $ + * $Revision: #77 $ + * $Date: 2009/04/21 $ + * $Change: 1237475 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ +#ifndef DWC_DEVICE_ONLY + +#include "dwc_otg_hcd.h" +#include "dwc_otg_regs.h" + +/** @file + * This file contains the implementation of the HCD Interrupt handlers. + */ + +/** This function handles interrupts for the HCD. */ +int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) +{ + int retval = 0; + + dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if; + gintsts_data_t gintsts; +#ifdef DEBUG + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; + + //GRAYG: debugging + if (NULL == global_regs) { + DWC_DEBUGPL(DBG_HCD, "**** NULL regs: dwc_otg_hcd=%p " + "core_if=%p\n", + dwc_otg_hcd, global_regs); + return retval; + } +#endif + + /* Check if HOST Mode */ + if (dwc_otg_is_host_mode(core_if)) { + gintsts.d32 = dwc_otg_read_core_intr(core_if); + if (!gintsts.d32) { + return 0; + } +#ifdef DEBUG + /* Don't print debug message in the interrupt handler on SOF */ +#ifndef DEBUG_SOF + if (gintsts.d32 != DWC_SOF_INTR_MASK) +#endif + DWC_DEBUGPL(DBG_HCD, "\n"); +#endif + +#ifdef DEBUG +#ifndef DEBUG_SOF + if (gintsts.d32 != DWC_SOF_INTR_MASK) +#endif + DWC_DEBUGPL(DBG_HCD, + "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x core_if=%p\n", + gintsts.d32, core_if); +#endif + + if (gintsts.b.sofintr) { + retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd); + } + if (gintsts.b.rxstsqlvl) { + retval |= + dwc_otg_hcd_handle_rx_status_q_level_intr + (dwc_otg_hcd); + } + if (gintsts.b.nptxfempty) { + retval |= + dwc_otg_hcd_handle_np_tx_fifo_empty_intr + (dwc_otg_hcd); + } + if (gintsts.b.i2cintr) { + /** @todo Implement i2cintr handler. */ + } + if (gintsts.b.portintr) { + retval |= dwc_otg_hcd_handle_port_intr(dwc_otg_hcd); + } + if (gintsts.b.hcintr) { + retval |= dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd); + } + if (gintsts.b.ptxfempty) { + retval |= + dwc_otg_hcd_handle_perio_tx_fifo_empty_intr + (dwc_otg_hcd); + } +#ifdef DEBUG +#ifndef DEBUG_SOF + if (gintsts.d32 != DWC_SOF_INTR_MASK) +#endif + { + DWC_DEBUGPL(DBG_HCD, + "DWC OTG HCD Finished Servicing Interrupts\n"); + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintsts=0x%08x\n", + dwc_read_reg32(&global_regs->gintsts)); + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintmsk=0x%08x\n", + dwc_read_reg32(&global_regs->gintmsk)); + } +#endif + +#ifdef DEBUG +#ifndef DEBUG_SOF + if (gintsts.d32 != DWC_SOF_INTR_MASK) +#endif + DWC_DEBUGPL(DBG_HCD, "\n"); +#endif + + } + + return retval; +} + +#ifdef DWC_TRACK_MISSED_SOFS +#warning Compiling code to track missed SOFs +#define FRAME_NUM_ARRAY_SIZE 1000 +/** + * This function is for debug only. + */ +static inline void track_missed_sofs(uint16_t curr_frame_number) +{ + static uint16_t frame_num_array[FRAME_NUM_ARRAY_SIZE]; + static uint16_t last_frame_num_array[FRAME_NUM_ARRAY_SIZE]; + static int frame_num_idx = 0; + static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM; + static int dumped_frame_num_array = 0; + + if (frame_num_idx < FRAME_NUM_ARRAY_SIZE) { + if (((last_frame_num + 1) & DWC_HFNUM_MAX_FRNUM) != + curr_frame_number) { + frame_num_array[frame_num_idx] = curr_frame_number; + last_frame_num_array[frame_num_idx++] = last_frame_num; + } + } else if (!dumped_frame_num_array) { + int i; + DWC_PRINTF("Frame Last Frame\n"); + DWC_PRINTF("----- ----------\n"); + for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) { + DWC_PRINTF("0x%04x 0x%04x\n", + frame_num_array[i], last_frame_num_array[i]); + } + dumped_frame_num_array = 1; + } + last_frame_num = curr_frame_number; +} +#endif + +/** + * Handles the start-of-frame interrupt in host mode. Non-periodic + * transactions may be queued to the DWC_otg controller for the current + * (micro)frame. Periodic transactions may be queued to the controller for the + * next (micro)frame. + */ +int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd) +{ + hfnum_data_t hfnum; + dwc_list_link_t *qh_entry; + dwc_otg_qh_t *qh; + dwc_otg_transaction_type_e tr_type; + gintsts_data_t gintsts = {.d32 = 0 }; + + hfnum.d32 = + dwc_read_reg32(&hcd->core_if->host_if->host_global_regs->hfnum); + +#ifdef DEBUG_SOF + DWC_DEBUGPL(DBG_HCD, "--Start of Frame Interrupt--\n"); +#endif + hcd->frame_number = hfnum.b.frnum; + +#ifdef DEBUG + hcd->frrem_accum += hfnum.b.frrem; + hcd->frrem_samples++; +#endif + +#ifdef DWC_TRACK_MISSED_SOFS + track_missed_sofs(hcd->frame_number); +#endif + /* Determine whether any periodic QHs should be executed. */ + qh_entry = DWC_LIST_FIRST(&hcd->periodic_sched_inactive); + while (qh_entry != &hcd->periodic_sched_inactive) { + qh = DWC_LIST_ENTRY(qh_entry, dwc_otg_qh_t, qh_list_entry); + qh_entry = qh_entry->next; + if (dwc_frame_num_le(qh->sched_frame, hcd->frame_number)) { + /* + * Move QH to the ready list to be executed next + * (micro)frame. + */ + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready, + &qh->qh_list_entry); + } + } + tr_type = dwc_otg_hcd_select_transactions(hcd); + if (tr_type != DWC_OTG_TRANSACTION_NONE) { + dwc_otg_hcd_queue_transactions(hcd, tr_type); + } + + /* Clear interrupt */ + gintsts.b.sofintr = 1; + dwc_write_reg32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32); + + return 1; +} + +/** Handles the Rx Status Queue Level Interrupt, which indicates that there is at + * least one packet in the Rx FIFO. The packets are moved from the FIFO to + * memory if the DWC_otg controller is operating in Slave mode. */ +int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t * dwc_otg_hcd) +{ + host_grxsts_data_t grxsts; + dwc_hc_t *hc = NULL; + + DWC_DEBUGPL(DBG_HCD, "--RxStsQ Level Interrupt--\n"); + + grxsts.d32 = + dwc_read_reg32(&dwc_otg_hcd->core_if->core_global_regs->grxstsp); + + hc = dwc_otg_hcd->hc_ptr_array[grxsts.b.chnum]; + + /* Packet Status */ + DWC_DEBUGPL(DBG_HCDV, " Ch num = %d\n", grxsts.b.chnum); + DWC_DEBUGPL(DBG_HCDV, " Count = %d\n", grxsts.b.bcnt); + DWC_DEBUGPL(DBG_HCDV, " DPID = %d, hc.dpid = %d\n", grxsts.b.dpid, + hc->data_pid_start); + DWC_DEBUGPL(DBG_HCDV, " PStatus = %d\n", grxsts.b.pktsts); + + switch (grxsts.b.pktsts) { + case DWC_GRXSTS_PKTSTS_IN: + /* Read the data into the host buffer. */ + if (grxsts.b.bcnt > 0) { + dwc_otg_read_packet(dwc_otg_hcd->core_if, + hc->xfer_buff, grxsts.b.bcnt); + + /* Update the HC fields for the next packet received. */ + hc->xfer_count += grxsts.b.bcnt; + hc->xfer_buff += grxsts.b.bcnt; + } + + case DWC_GRXSTS_PKTSTS_IN_XFER_COMP: + case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR: + case DWC_GRXSTS_PKTSTS_CH_HALTED: + /* Handled in interrupt, just ignore data */ + break; + default: + DWC_ERROR("RX_STS_Q Interrupt: Unknown status %d\n", + grxsts.b.pktsts); + break; + } + + return 1; +} + +/** This interrupt occurs when the non-periodic Tx FIFO is half-empty. More + * data packets may be written to the FIFO for OUT transfers. More requests + * may be written to the non-periodic request queue for IN transfers. This + * interrupt is enabled only in Slave mode. */ +int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd) +{ + DWC_DEBUGPL(DBG_HCD, "--Non-Periodic TxFIFO Empty Interrupt--\n"); + dwc_otg_hcd_queue_transactions(dwc_otg_hcd, + DWC_OTG_TRANSACTION_NON_PERIODIC); + return 1; +} + +/** This interrupt occurs when the periodic Tx FIFO is half-empty. More data + * packets may be written to the FIFO for OUT transfers. More requests may be + * written to the periodic request queue for IN transfers. This interrupt is + * enabled only in Slave mode. */ +int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd) +{ + DWC_DEBUGPL(DBG_HCD, "--Periodic TxFIFO Empty Interrupt--\n"); + dwc_otg_hcd_queue_transactions(dwc_otg_hcd, + DWC_OTG_TRANSACTION_PERIODIC); + return 1; +} + +/** There are multiple conditions that can cause a port interrupt. This function + * determines which interrupt conditions have occurred and handles them + * appropriately. */ +int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd) +{ + int retval = 0; + hprt0_data_t hprt0; + hprt0_data_t hprt0_modify; + + hprt0.d32 = dwc_read_reg32(dwc_otg_hcd->core_if->host_if->hprt0); + hprt0_modify.d32 = dwc_read_reg32(dwc_otg_hcd->core_if->host_if->hprt0); + + /* Clear appropriate bits in HPRT0 to clear the interrupt bit in + * GINTSTS */ + + hprt0_modify.b.prtena = 0; + hprt0_modify.b.prtconndet = 0; + hprt0_modify.b.prtenchng = 0; + hprt0_modify.b.prtovrcurrchng = 0; + + /* Port Connect Detected + * Set flag and clear if detected */ + if (hprt0.b.prtconndet) { + DWC_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x " + "Port Connect Detected--\n", hprt0.d32); + dwc_otg_hcd->flags.b.port_connect_status_change = 1; + dwc_otg_hcd->flags.b.port_connect_status = 1; + hprt0_modify.b.prtconndet = 1; + + /* B-Device has connected, Delete the connection timer. */ + DWC_TIMER_CANCEL(dwc_otg_hcd->conn_timer); + + /* The Hub driver asserts a reset when it sees port connect + * status change flag */ + retval |= 1; + } + + /* Port Enable Changed + * Clear if detected - Set internal flag if disabled */ + if (hprt0.b.prtenchng) { + DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x " + "Port Enable Changed--\n", hprt0.d32); + hprt0_modify.b.prtenchng = 1; + if (hprt0.b.prtena == 1) { + int do_reset = 0; + dwc_otg_core_params_t *params = + dwc_otg_hcd->core_if->core_params; + dwc_otg_core_global_regs_t *global_regs = + dwc_otg_hcd->core_if->core_global_regs; + dwc_otg_host_if_t *host_if = + dwc_otg_hcd->core_if->host_if; + + /* Check if we need to adjust the PHY clock speed for + * low power and adjust it */ + if (params->host_support_fs_ls_low_power) { + gusbcfg_data_t usbcfg; + + usbcfg.d32 = + dwc_read_reg32(&global_regs->gusbcfg); + + if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED + || hprt0.b.prtspd == + DWC_HPRT0_PRTSPD_FULL_SPEED) { + /* + * Low power + */ + hcfg_data_t hcfg; + if (usbcfg.b.phylpwrclksel == 0) { + /* Set PHY low power clock select for FS/LS devices */ + usbcfg.b.phylpwrclksel = 1; + dwc_write_reg32(&global_regs-> + gusbcfg, + usbcfg.d32); + do_reset = 1; + } + + hcfg.d32 = + dwc_read_reg32(&host_if-> + host_global_regs->hcfg); + + if (hprt0.b.prtspd == + DWC_HPRT0_PRTSPD_LOW_SPEED + && params-> + host_ls_low_power_phy_clk == + DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ) + { + /* 6 MHZ */ + DWC_DEBUGPL(DBG_CIL, + "FS_PHY programming HCFG to 6 MHz (Low Power)\n"); + if (hcfg.b.fslspclksel != + DWC_HCFG_6_MHZ) { + hcfg.b.fslspclksel = + DWC_HCFG_6_MHZ; + dwc_write_reg32 + (&host_if-> + host_global_regs-> + hcfg, hcfg.d32); + do_reset = 1; + } + } else { + /* 48 MHZ */ + DWC_DEBUGPL(DBG_CIL, + "FS_PHY programming HCFG to 48 MHz ()\n"); + if (hcfg.b.fslspclksel != + DWC_HCFG_48_MHZ) { + hcfg.b.fslspclksel = + DWC_HCFG_48_MHZ; + dwc_write_reg32 + (&host_if-> + host_global_regs-> + hcfg, hcfg.d32); + do_reset = 1; + } + } + } else { + /* + * Not low power + */ + if (usbcfg.b.phylpwrclksel == 1) { + usbcfg.b.phylpwrclksel = 0; + dwc_write_reg32(&global_regs-> + gusbcfg, + usbcfg.d32); + do_reset = 1; + } + } + + if (do_reset) { + DWC_TASK_SCHEDULE(dwc_otg_hcd-> + reset_tasklet); + } + } + + if (!do_reset) { + /* Port has been enabled set the reset change flag */ + dwc_otg_hcd->flags.b.port_reset_change = 1; + } + } else { + dwc_otg_hcd->flags.b.port_enable_change = 1; + } + retval |= 1; + } + + /** Overcurrent Change Interrupt */ + if (hprt0.b.prtovrcurrchng) { + DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x " + "Port Overcurrent Changed--\n", hprt0.d32); + dwc_otg_hcd->flags.b.port_over_current_change = 1; + hprt0_modify.b.prtovrcurrchng = 1; + retval |= 1; + } + + /* Clear Port Interrupts */ + dwc_write_reg32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32); + + return retval; +} + +/** This interrupt indicates that one or more host channels has a pending + * interrupt. There are multiple conditions that can cause each host channel + * interrupt. This function determines which conditions have occurred for each + * host channel interrupt and handles them appropriately. */ +int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd) +{ + int i; + int retval = 0; + haint_data_t haint; + + /* Clear appropriate bits in HCINTn to clear the interrupt bit in + * GINTSTS */ + + haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if); + + for (i = 0; i < dwc_otg_hcd->core_if->core_params->host_channels; i++) { + if (haint.b2.chint & (1 << i)) { + retval |= dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd, i); + } + } + + return retval; +} + + + +/** + * Gets the actual length of a transfer after the transfer halts. _halt_status + * holds the reason for the halt. + * + * For IN transfers where halt_status is DWC_OTG_HC_XFER_COMPLETE, + * *short_read is set to 1 upon return if less than the requested + * number of bytes were transferred. Otherwise, *short_read is set to 0 upon + * return. short_read may also be NULL on entry, in which case it remains + * unchanged. + */ +static uint32_t get_actual_xfer_length(dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_qtd_t * qtd, + dwc_otg_halt_status_e halt_status, + int *short_read) +{ + hctsiz_data_t hctsiz; + uint32_t length; + + if (short_read != NULL) { + *short_read = 0; + } + hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz); + + if (halt_status == DWC_OTG_HC_XFER_COMPLETE) { + if (hc->ep_is_in) { + length = hc->xfer_len - hctsiz.b.xfersize; + if (short_read != NULL) { + *short_read = (hctsiz.b.xfersize != 0); + } + } else if (hc->qh->do_split) { + length = qtd->ssplit_out_xfer_count; + } else { + length = hc->xfer_len; + } + } else { + /* + * Must use the hctsiz.pktcnt field to determine how much data + * has been transferred. This field reflects the number of + * packets that have been transferred via the USB. This is + * always an integral number of packets if the transfer was + * halted before its normal completion. (Can't use the + * hctsiz.xfersize field because that reflects the number of + * bytes transferred via the AHB, not the USB). + */ + length = + (hc->start_pkt_count - hctsiz.b.pktcnt) * hc->max_packet; + } + + return length; +} + +/** + * Updates the state of the URB after a Transfer Complete interrupt on the + * host channel. Updates the actual_length field of the URB based on the + * number of bytes transferred via the host channel. Sets the URB status + * if the data transfer is finished. + * + * @return 1 if the data transfer specified by the URB is completely finished, + * 0 otherwise. + */ +static int update_urb_state_xfer_comp(dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_hcd_urb_t * urb, + dwc_otg_qtd_t * qtd) +{ + int xfer_done = 0; + int short_read = 0; + + int xfer_length; + + xfer_length = get_actual_xfer_length(hc, hc_regs, qtd, + DWC_OTG_HC_XFER_COMPLETE, + &short_read); + + + /* non DWORD-aligned buffer case handling. */ + if (hc->align_buff && xfer_length && hc->ep_is_in) { + dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf, xfer_length); + } + + urb->actual_length += xfer_length; + + if(xfer_length && (hc->ep_type == DWC_OTG_EP_TYPE_BULK) && + (urb->flags & URB_SEND_ZERO_PACKET) && (urb->actual_length == urb->length) && + !(urb->length % hc->max_packet)) { + xfer_done = 0; + } else if (short_read || urb->actual_length == urb->length) { + xfer_done = 1; + urb->status = 0; + } + +#ifdef DEBUG + { + hctsiz_data_t hctsiz; + hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz); + DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n", + __func__, (hc->ep_is_in ? "IN" : "OUT"), + hc->hc_num); + DWC_DEBUGPL(DBG_HCDV, " hc->xfer_len %d\n", hc->xfer_len); + DWC_DEBUGPL(DBG_HCDV, " hctsiz.xfersize %d\n", + hctsiz.b.xfersize); + DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n", + urb->length); + DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n", + urb->actual_length); + DWC_DEBUGPL(DBG_HCDV, " short_read %d, xfer_done %d\n", + short_read, xfer_done); + } +#endif + + return xfer_done; +} + +/* + * Save the starting data toggle for the next transfer. The data toggle is + * saved in the QH for non-control transfers and it's saved in the QTD for + * control transfers. + */ +void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, dwc_otg_qtd_t * qtd) +{ + hctsiz_data_t hctsiz; + hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz); + + if (hc->ep_type != DWC_OTG_EP_TYPE_CONTROL) { + dwc_otg_qh_t *qh = hc->qh; + if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) { + qh->data_toggle = DWC_OTG_HC_PID_DATA0; + } else { + qh->data_toggle = DWC_OTG_HC_PID_DATA1; + } + } else { + if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) { + qtd->data_toggle = DWC_OTG_HC_PID_DATA0; + } else { + qtd->data_toggle = DWC_OTG_HC_PID_DATA1; + } + } +} + +/** + * Updates the state of an Isochronous URB when the transfer is stopped for + * any reason. The fields of the current entry in the frame descriptor array + * are set based on the transfer state and the input _halt_status. Completes + * the Isochronous URB if all the URB frames have been completed. + * + * @return DWC_OTG_HC_XFER_COMPLETE if there are more frames remaining to be + * transferred in the URB. Otherwise return DWC_OTG_HC_XFER_URB_COMPLETE. + */ +static dwc_otg_halt_status_e +update_isoc_urb_state(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status) +{ + dwc_otg_hcd_urb_t *urb = qtd->urb; + dwc_otg_halt_status_e ret_val = halt_status; + struct dwc_otg_hcd_iso_packet_desc *frame_desc; + + frame_desc = &urb->iso_descs[qtd->isoc_frame_index]; + switch (halt_status) { + case DWC_OTG_HC_XFER_COMPLETE: + frame_desc->status = 0; + frame_desc->actual_length = + get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL); + + /* non DWORD-aligned buffer case handling. */ + if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) { + dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset, + hc->qh->dw_align_buf, frame_desc->actual_length); + } + + break; + case DWC_OTG_HC_XFER_FRAME_OVERRUN: + urb->error_count++; + if (hc->ep_is_in) { + frame_desc->status = -DWC_E_NO_STREAM_RES; + } else { + frame_desc->status = -DWC_E_COMMUNICATION; + } + frame_desc->actual_length = 0; + break; + case DWC_OTG_HC_XFER_BABBLE_ERR: + urb->error_count++; + frame_desc->status = -DWC_E_OVERFLOW; + /* Don't need to update actual_length in this case. */ + break; + case DWC_OTG_HC_XFER_XACT_ERR: + urb->error_count++; + frame_desc->status = -DWC_E_PROTOCOL; + frame_desc->actual_length = + get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL); + + /* non DWORD-aligned buffer case handling. */ + if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) { + dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset, + hc->qh->dw_align_buf, frame_desc->actual_length); + } + /* Skip whole frame */ + if (hc->qh->do_split && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && + hc->ep_is_in && hcd->core_if->dma_enable) { + qtd->complete_split = 0; + qtd->isoc_split_offset = 0; + } + + break; + default: + DWC_ASSERT(1, "Unhandled _halt_status (%d)\n", halt_status); + break; + } + if (++qtd->isoc_frame_index == urb->packet_count) { + /* + * urb->status is not used for isoc transfers. + * The individual frame_desc statuses are used instead. + */ + hcd->fops->complete(hcd, urb->priv, urb, 0); + ret_val = DWC_OTG_HC_XFER_URB_COMPLETE; + } else { + ret_val = DWC_OTG_HC_XFER_COMPLETE; + } + return ret_val; +} + +/** + * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic + * QHs, removes the QH from the active non-periodic schedule. If any QTDs are + * still linked to the QH, the QH is added to the end of the inactive + * non-periodic schedule. For periodic QHs, removes the QH from the periodic + * schedule if no more QTDs are linked to the QH. + */ +static void deactivate_qh(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, int free_qtd) +{ + int continue_split = 0; + dwc_otg_qtd_t *qtd; + + DWC_DEBUGPL(DBG_HCDV, " %s(%p,%p,%d)\n", __func__, hcd, qh, free_qtd); + + qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); + + if (qtd->complete_split) { + continue_split = 1; + } else if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID || + qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END) { + continue_split = 1; + } + + if (free_qtd) { + dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh); + continue_split = 0; + } + + qh->channel = NULL; + dwc_otg_hcd_qh_deactivate(hcd, qh, continue_split); +} + +/** + * Releases a host channel for use by other transfers. Attempts to select and + * queue more transactions since at least one host channel is available. + * + * @param hcd The HCD state structure. + * @param hc The host channel to release. + * @param qtd The QTD associated with the host channel. This QTD may be freed + * if the transfer is complete or an error has occurred. + * @param halt_status Reason the channel is being released. This status + * determines the actions taken by this function. + */ +static void release_channel(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_qtd_t * qtd, + dwc_otg_halt_status_e halt_status) +{ + dwc_otg_transaction_type_e tr_type; + int free_qtd; + + DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d, xfer_len %d\n", + __func__, hc->hc_num, halt_status, hc->xfer_len); + +#ifdef HW2937_WORKAROUND + if (hcd->hw2937_assigned_channels & (1<hc_num)) + { + if ((hcd->hw2937_assigned_channels &= ~(1<hc_num)) == 0) + hcd->hw2937_xfer_mode = HW2937_XFER_MODE_IDLE; + DWC_DEBUGPL(DBG_HW2937, " release %d, hw2937_ac -> %x\n", hc->hc_num, hcd->hw2937_assigned_channels); + } + else + { + DWC_DEBUGPL(DBG_ANY, " Unexpected release %d (hw2937_ac = %x)\n", hc->hc_num, hcd->hw2937_assigned_channels); + } +#endif + + switch (halt_status) { + case DWC_OTG_HC_XFER_URB_COMPLETE: + free_qtd = 1; + break; + case DWC_OTG_HC_XFER_AHB_ERR: + case DWC_OTG_HC_XFER_STALL: + case DWC_OTG_HC_XFER_BABBLE_ERR: + free_qtd = 1; + break; + case DWC_OTG_HC_XFER_XACT_ERR: + if (qtd->error_count >= 3) { + DWC_DEBUGPL(DBG_HCDV, + " Complete URB with transaction error\n"); + free_qtd = 1; + qtd->urb->status = -DWC_E_PROTOCOL; + hcd->fops->complete(hcd, qtd->urb->priv, + qtd->urb, -DWC_E_PROTOCOL); + } else { + free_qtd = 0; + } + break; + case DWC_OTG_HC_XFER_URB_DEQUEUE: + /* + * The QTD has already been removed and the QH has been + * deactivated. Don't want to do anything except release the + * host channel and try to queue more transfers. + */ + goto cleanup; + case DWC_OTG_HC_XFER_NO_HALT_STATUS: + free_qtd = 0; + break; + default: + free_qtd = 0; + break; + } + + deactivate_qh(hcd, hc->qh, free_qtd); + + cleanup: + /* + * Release the host channel for use by other transfers. The cleanup + * function clears the channel interrupt enables and conditions, so + * there's no need to clear the Channel Halted interrupt separately. + */ + dwc_otg_hc_cleanup(hcd->core_if, hc); + DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry); + + switch (hc->ep_type) { + case DWC_OTG_EP_TYPE_CONTROL: + case DWC_OTG_EP_TYPE_BULK: + hcd->non_periodic_channels--; + break; + + default: + /* + * Don't release reservations for periodic channels here. + * That's done when a periodic transfer is descheduled (i.e. + * when the QH is removed from the periodic schedule). + */ + break; + } + + /* Try to queue more transfers now that there's a free channel. */ + tr_type = dwc_otg_hcd_select_transactions(hcd); + if (tr_type != DWC_OTG_TRANSACTION_NONE) { + dwc_otg_hcd_queue_transactions(hcd, tr_type); + } +} + + +/** + * Halts a host channel. If the channel cannot be halted immediately because + * the request queue is full, this function ensures that the FIFO empty + * interrupt for the appropriate queue is enabled so that the halt request can + * be queued when there is space in the request queue. + * + * This function may also be called in DMA mode. In that case, the channel is + * simply released since the core always halts the channel automatically in + * DMA mode. + */ +static void halt_channel(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status) +{ + if (hcd->core_if->dma_enable) { + release_channel(hcd, hc, qtd, halt_status); + return; + } + + /* Slave mode processing... */ + dwc_otg_hc_halt(hcd->core_if, hc, halt_status); + + if (hc->halt_on_queue) { + gintmsk_data_t gintmsk = {.d32 = 0 }; + dwc_otg_core_global_regs_t *global_regs; + global_regs = hcd->core_if->core_global_regs; + + if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL || + hc->ep_type == DWC_OTG_EP_TYPE_BULK) { + /* + * Make sure the Non-periodic Tx FIFO empty interrupt + * is enabled so that the non-periodic schedule will + * be processed. + */ + gintmsk.b.nptxfempty = 1; + dwc_modify_reg32(&global_regs->gintmsk, 0, gintmsk.d32); + } else { + /* + * Move the QH from the periodic queued schedule to + * the periodic assigned schedule. This allows the + * halt to be queued when the periodic schedule is + * processed. + */ + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned, + &hc->qh->qh_list_entry); + + /* + * Make sure the Periodic Tx FIFO Empty interrupt is + * enabled so that the periodic schedule will be + * processed. + */ + gintmsk.b.ptxfempty = 1; + dwc_modify_reg32(&global_regs->gintmsk, 0, gintmsk.d32); + } + } +} + +/** + * Performs common cleanup for non-periodic transfers after a Transfer + * Complete interrupt. This function should be called after any endpoint type + * specific handling is finished to release the host channel. + */ +static void complete_non_periodic_xfer(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_qtd_t * qtd, + dwc_otg_halt_status_e halt_status) +{ + hcint_data_t hcint; + + qtd->error_count = 0; + + hcint.d32 = dwc_read_reg32(&hc_regs->hcint); + if (hcint.b.nyet) { + /* + * Got a NYET on the last transaction of the transfer. This + * means that the endpoint should be in the PING state at the + * beginning of the next transfer. + */ + hc->qh->ping_state = 1; + clear_hc_int(hc_regs, nyet); + } + + /* + * Always halt and release the host channel to make it available for + * more transfers. There may still be more phases for a control + * transfer or more data packets for a bulk transfer at this point, + * but the host channel is still halted. A channel will be reassigned + * to the transfer when the non-periodic schedule is processed after + * the channel is released. This allows transactions to be queued + * properly via dwc_otg_hcd_queue_transactions, which also enables the + * Tx FIFO Empty interrupt if necessary. + */ + if (hc->ep_is_in) { + /* + * IN transfers in Slave mode require an explicit disable to + * halt the channel. (In DMA mode, this call simply releases + * the channel.) + */ + halt_channel(hcd, hc, qtd, halt_status); + } else { + /* + * The channel is automatically disabled by the core for OUT + * transfers in Slave mode. + */ + release_channel(hcd, hc, qtd, halt_status); + } +} + +/** + * Performs common cleanup for periodic transfers after a Transfer Complete + * interrupt. This function should be called after any endpoint type specific + * handling is finished to release the host channel. + */ +static void complete_periodic_xfer(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_qtd_t * qtd, + dwc_otg_halt_status_e halt_status) +{ + hctsiz_data_t hctsiz; + qtd->error_count = 0; + + hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz); + if (!hc->ep_is_in || hctsiz.b.pktcnt == 0) { + /* Core halts channel in these cases. */ + release_channel(hcd, hc, qtd, halt_status); + } else { + /* Flush any outstanding requests from the Tx queue. */ + halt_channel(hcd, hc, qtd, halt_status); + } +} + +static int32_t handle_xfercomp_isoc_split_in(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_qtd_t * qtd) +{ + uint32_t len; + struct dwc_otg_hcd_iso_packet_desc *frame_desc; + frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; + + len = get_actual_xfer_length(hc, hc_regs, qtd, + DWC_OTG_HC_XFER_COMPLETE, + NULL); + + if (!len) { + qtd->complete_split = 0; + qtd->isoc_split_offset = 0; + return 0; + } + frame_desc->actual_length += len; + + if (hc->align_buff && len) + dwc_memcpy(qtd->urb->buf + frame_desc->offset + qtd->isoc_split_offset, + hc->qh->dw_align_buf, + len); + qtd->isoc_split_offset += len; + + if (frame_desc->length == frame_desc->actual_length) { + frame_desc->status = 0; + qtd->isoc_frame_index++; + qtd->complete_split = 0; + qtd->isoc_split_offset = 0; + } + + if (qtd->isoc_frame_index == qtd->urb->packet_count) { + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0); + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); + } else { + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS); + } + + return 1; /* Indicates that channel released */ +} +/** + * Handles a host channel Transfer Complete interrupt. This handler may be + * called in either DMA mode or Slave mode. + */ +static int32_t handle_hc_xfercomp_intr(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_qtd_t * qtd) +{ + int urb_xfer_done; + dwc_otg_halt_status_e halt_status = DWC_OTG_HC_XFER_COMPLETE; + dwc_otg_hcd_urb_t *urb = qtd->urb; + int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info); + + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " + "Transfer Complete--\n", hc->hc_num); + + if (hcd->core_if->dma_desc_enable) { + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, halt_status); + if (pipe_type == UE_ISOCHRONOUS) { + /* Do not disable the interrupt, just clear it */ + clear_hc_int(hc_regs, xfercomp); + return 1; + } + goto handle_xfercomp_done; + } + + /* + * Handle xfer complete on CSPLIT. + */ + + if (hc->qh->do_split) { + if ((hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && hc->ep_is_in && hcd->core_if->dma_enable) { + if (qtd->complete_split && handle_xfercomp_isoc_split_in(hcd, hc, hc_regs, qtd)) + goto handle_xfercomp_done; + } + else { + qtd->complete_split = 0; + } + } + + /* Update the QTD and URB states. */ + switch (pipe_type) { + case UE_CONTROL: + switch (qtd->control_phase) { + case DWC_OTG_CONTROL_SETUP: + if (urb->length > 0) { + qtd->control_phase = DWC_OTG_CONTROL_DATA; + } else { + qtd->control_phase = DWC_OTG_CONTROL_STATUS; + } + DWC_DEBUGPL(DBG_HCDV, + " Control setup transaction done\n"); + halt_status = DWC_OTG_HC_XFER_COMPLETE; + break; + case DWC_OTG_CONTROL_DATA:{ + urb_xfer_done = + update_urb_state_xfer_comp(hc, hc_regs, urb, + qtd); + if (urb_xfer_done) { + qtd->control_phase = + DWC_OTG_CONTROL_STATUS; + DWC_DEBUGPL(DBG_HCDV, + " Control data transfer done\n"); + } else { + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); + } + halt_status = DWC_OTG_HC_XFER_COMPLETE; + break; + } + case DWC_OTG_CONTROL_STATUS: + DWC_DEBUGPL(DBG_HCDV, " Control transfer complete\n"); + if (urb->status == -DWC_E_IN_PROGRESS) { + urb->status = 0; + } + hcd->fops->complete(hcd, urb->priv, urb, urb->status); + halt_status = DWC_OTG_HC_XFER_URB_COMPLETE; + break; + } + + complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status); + break; + case UE_BULK: + DWC_DEBUGPL(DBG_HCDV, " Bulk transfer complete\n"); + urb_xfer_done = + update_urb_state_xfer_comp(hc, hc_regs, urb, qtd); + if (urb_xfer_done) { + hcd->fops->complete(hcd, urb->priv, urb, urb->status); + halt_status = DWC_OTG_HC_XFER_URB_COMPLETE; + } else { + halt_status = DWC_OTG_HC_XFER_COMPLETE; + } + + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); + complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status); + break; + case UE_INTERRUPT: + DWC_DEBUGPL(DBG_HCDV, " Interrupt transfer complete\n"); + update_urb_state_xfer_comp(hc, hc_regs, urb, qtd); + + /* + * Interrupt URB is done on the first transfer complete + * interrupt. + */ + hcd->fops->complete(hcd, urb->priv, urb, urb->status); + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); + complete_periodic_xfer(hcd, hc, hc_regs, qtd, + DWC_OTG_HC_XFER_URB_COMPLETE); + break; + case UE_ISOCHRONOUS: + DWC_DEBUGPL(DBG_HCDV, " Isochronous transfer complete\n"); + if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_ALL) { + halt_status = + update_isoc_urb_state(hcd, hc, hc_regs, qtd, + DWC_OTG_HC_XFER_COMPLETE); + } + complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status); + break; + } + +handle_xfercomp_done: + disable_hc_int(hc_regs, xfercompl); + + return 1; +} + +/** + * Handles a host channel STALL interrupt. This handler may be called in + * either DMA mode or Slave mode. + */ +static int32_t handle_hc_stall_intr(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_qtd_t * qtd) +{ + dwc_otg_hcd_urb_t *urb = qtd->urb; + int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info); + + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " + "STALL Received--\n", hc->hc_num); + + if (hcd->core_if->dma_desc_enable) { + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_STALL); + goto handle_stall_done; + } + + if (pipe_type == UE_CONTROL) { + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE); + } + + if (pipe_type == UE_BULK || pipe_type == UE_INTERRUPT) { + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE); + /* + * USB protocol requires resetting the data toggle for bulk + * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT) + * setup command is issued to the endpoint. Anticipate the + * CLEAR_FEATURE command since a STALL has occurred and reset + * the data toggle now. + */ + hc->qh->data_toggle = 0; + } + + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_STALL); + +handle_stall_done: + disable_hc_int(hc_regs, stall); + + return 1; +} + +/* + * Updates the state of the URB when a transfer has been stopped due to an + * abnormal condition before the transfer completes. Modifies the + * actual_length field of the URB to reflect the number of bytes that have + * actually been transferred via the host channel. + */ +static void update_urb_state_xfer_intr(dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_hcd_urb_t * urb, + dwc_otg_qtd_t * qtd, + dwc_otg_halt_status_e halt_status) +{ + uint32_t bytes_transferred = get_actual_xfer_length(hc, hc_regs, qtd, + halt_status, NULL); + /* non DWORD-aligned buffer case handling. */ + if (hc->align_buff && bytes_transferred && hc->ep_is_in) { + dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf, bytes_transferred); + } + + urb->actual_length += bytes_transferred; + +#ifdef DEBUG + { + hctsiz_data_t hctsiz; + hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz); + DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n", + __func__, (hc->ep_is_in ? "IN" : "OUT"), + hc->hc_num); + DWC_DEBUGPL(DBG_HCDV, " hc->start_pkt_count %d\n", + hc->start_pkt_count); + DWC_DEBUGPL(DBG_HCDV, " hctsiz.pktcnt %d\n", hctsiz.b.pktcnt); + DWC_DEBUGPL(DBG_HCDV, " hc->max_packet %d\n", hc->max_packet); + DWC_DEBUGPL(DBG_HCDV, " bytes_transferred %d\n", + bytes_transferred); + DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n", + urb->actual_length); + DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n", + urb->length); + } +#endif +} + +/** + * Handles a host channel NAK interrupt. This handler may be called in either + * DMA mode or Slave mode. + */ +static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_qtd_t * qtd) +{ + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " + "NAK Received--\n", hc->hc_num); + + /* + * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and + * interrupt. Re-start the SSPLIT transfer. + */ + if (hc->do_split) { + if (hc->complete_split) { + qtd->error_count = 0; + } + qtd->complete_split = 0; + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK); + goto handle_nak_done; + } + + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) { + case UE_CONTROL: + case UE_BULK: + if (hcd->core_if->dma_enable && hc->ep_is_in) { +#ifdef HW2937_WORKAROUND + if (hc->halt_status == DWC_OTG_HC_XFER_PAUSE_IN) { + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK); + } +#endif + /* + * NAK interrupts are enabled on bulk/control IN + * transfers in DMA mode for the sole purpose of + * resetting the error count after a transaction error + * occurs. The core will continue transferring data. + */ + qtd->error_count = 0; + goto handle_nak_done; + } + + /* + * NAK interrupts normally occur during OUT transfers in DMA + * or Slave mode. For IN transfers, more requests will be + * queued as request queue space is available. + */ + qtd->error_count = 0; + + if (!hc->qh->ping_state) { + update_urb_state_xfer_intr(hc, hc_regs, + qtd->urb, qtd, + DWC_OTG_HC_XFER_NAK); + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); + + if (hc->speed == DWC_OTG_EP_SPEED_HIGH) + hc->qh->ping_state = 1; + } + + /* + * Halt the channel so the transfer can be re-started from + * the appropriate point or the PING protocol will + * start/continue. + */ + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK); + break; + case UE_INTERRUPT: + qtd->error_count = 0; + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK); + break; + case UE_ISOCHRONOUS: +#ifdef HW2937_WORKAROUND + if (hc->halt_status == DWC_OTG_HC_XFER_PAUSE_IN) { + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK); + break; + } +#endif + /* Should never get called for isochronous transfers. */ + DWC_ASSERT(1, "NACK interrupt for ISOC transfer\n"); + break; + } + + handle_nak_done: + disable_hc_int(hc_regs, nak); + + return 1; +} + +/** + * Handles a host channel ACK interrupt. This interrupt is enabled when + * performing the PING protocol in Slave mode, when errors occur during + * either Slave mode or DMA mode, and during Start Split transactions. + */ +static int32_t handle_hc_ack_intr(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_qtd_t * qtd) +{ + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " + "ACK Received--\n", hc->hc_num); + + if (hc->do_split) { + /* + * Handle ACK on SSPLIT. + * ACK should not occur in CSPLIT. + */ + if (!hc->ep_is_in && hc->data_pid_start != DWC_OTG_HC_PID_SETUP) { + qtd->ssplit_out_xfer_count = hc->xfer_len; + } + if (!(hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in)) { + /* Don't need complete for isochronous out transfers. */ + qtd->complete_split = 1; + } + + /* ISOC OUT */ + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) { + switch (hc->xact_pos) { + case DWC_HCSPLIT_XACTPOS_ALL: + break; + case DWC_HCSPLIT_XACTPOS_END: + qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL; + qtd->isoc_split_offset = 0; + break; + case DWC_HCSPLIT_XACTPOS_BEGIN: + case DWC_HCSPLIT_XACTPOS_MID: + /* + * For BEGIN or MID, calculate the length for + * the next microframe to determine the correct + * SSPLIT token, either MID or END. + */ + { + struct dwc_otg_hcd_iso_packet_desc + *frame_desc; + + frame_desc = + &qtd->urb->iso_descs[qtd-> + isoc_frame_index]; + qtd->isoc_split_offset += 188; + + if ((frame_desc->length - + qtd->isoc_split_offset) <= 188) { + qtd->isoc_split_pos = + DWC_HCSPLIT_XACTPOS_END; + } else { + qtd->isoc_split_pos = + DWC_HCSPLIT_XACTPOS_MID; + } + + } + break; + } + } else { + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK); + } + } else { + qtd->error_count = 0; + + if (hc->qh->ping_state) { + hc->qh->ping_state = 0; + /* + * Halt the channel so the transfer can be re-started + * from the appropriate point. This only happens in + * Slave mode. In DMA mode, the ping_state is cleared + * when the transfer is started because the core + * automatically executes the PING, then the transfer. + */ + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK); + } +#ifdef HW2937_WORKAROUND + else if (hc->halt_status == DWC_OTG_HC_XFER_PAUSE_IN) { + dwc_otg_hc_regs_t *hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num]; + update_urb_state_xfer_intr(hc, hc_regs, qtd->urb, qtd, DWC_OTG_HC_XFER_PAUSE_IN); + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_PAUSE_IN); + } +#endif + } + + /* + * If the ACK occurred when _not_ in the PING state, let the channel + * continue transferring data after clearing the error count. + */ + + disable_hc_int(hc_regs, ack); + + return 1; +} + +/** + * Handles a host channel NYET interrupt. This interrupt should only occur on + * Bulk and Control OUT endpoints and for complete split transactions. If a + * NYET occurs at the same time as a Transfer Complete interrupt, it is + * handled in the xfercomp interrupt handler, not here. This handler may be + * called in either DMA mode or Slave mode. + */ +static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_qtd_t * qtd) +{ + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " + "NYET Received--\n", hc->hc_num); + + /* + * NYET on CSPLIT + * re-do the CSPLIT immediately on non-periodic + */ + if (hc->do_split && hc->complete_split) { + if (hc->ep_is_in && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && hcd->core_if->dma_enable) { + qtd->complete_split = 0; + qtd->isoc_split_offset = 0; + if (++qtd->isoc_frame_index == qtd->urb->packet_count) { + hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0); + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); + } + else + release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS); + goto handle_nyet_done; + } + + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR || + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { + int frnum = dwc_otg_hcd_get_frame_number(hcd); + + if (dwc_full_frame_num(frnum) != + dwc_full_frame_num(hc->qh->sched_frame)) { + /* + * No longer in the same full speed frame. + * Treat this as a transaction error. + */ +#if 0 + /** @todo Fix system performance so this can + * be treated as an error. Right now complete + * splits cannot be scheduled precisely enough + * due to other system activity, so this error + * occurs regularly in Slave mode. + */ + qtd->error_count++; +#endif + qtd->complete_split = 0; + halt_channel(hcd, hc, qtd, + DWC_OTG_HC_XFER_XACT_ERR); + /** @todo add support for isoc release */ + goto handle_nyet_done; + } + } + + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET); + goto handle_nyet_done; + } + + hc->qh->ping_state = 1; + qtd->error_count = 0; + + update_urb_state_xfer_intr(hc, hc_regs, qtd->urb, qtd, + DWC_OTG_HC_XFER_NYET); + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); + + /* + * Halt the channel and re-start the transfer so the PING + * protocol will start. + */ + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET); + + handle_nyet_done: + disable_hc_int(hc_regs, nyet); + return 1; +} + +/** + * Handles a host channel babble interrupt. This handler may be called in + * either DMA mode or Slave mode. + */ +static int32_t handle_hc_babble_intr(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_qtd_t * qtd) +{ + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " + "Babble Error--\n", hc->hc_num); + + if (hcd->core_if->dma_desc_enable) { + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_BABBLE_ERR); + goto handle_babble_done; + } + + if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) { + hcd->fops->complete(hcd, qtd->urb->priv, + qtd->urb, -DWC_E_OVERFLOW); + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_BABBLE_ERR); + } else { + dwc_otg_halt_status_e halt_status; + halt_status = update_isoc_urb_state(hcd, hc, hc_regs, qtd, + DWC_OTG_HC_XFER_BABBLE_ERR); + halt_channel(hcd, hc, qtd, halt_status); + } + +handle_babble_done: + disable_hc_int(hc_regs, bblerr); + return 1; +} + +/** + * Handles a host channel AHB error interrupt. This handler is only called in + * DMA mode. + */ +static int32_t handle_hc_ahberr_intr(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_qtd_t * qtd) +{ + hcchar_data_t hcchar; + hcsplt_data_t hcsplt; + hctsiz_data_t hctsiz; + uint32_t hcdma; + char *pipetype, *speed; + + dwc_otg_hcd_urb_t *urb = qtd->urb; + + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " + "AHB Error--\n", hc->hc_num); + + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt); + hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz); + hcdma = dwc_read_reg32(&hc_regs->hcdma); + + DWC_ERROR("AHB ERROR, Channel %d\n", hc->hc_num); + DWC_ERROR(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32); + DWC_ERROR(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma); + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Enqueue\n"); + DWC_ERROR(" Device address: %d\n", + dwc_otg_hcd_get_dev_addr(&urb->pipe_info)); + DWC_ERROR(" Endpoint: %d, %s\n", + dwc_otg_hcd_get_ep_num(&urb->pipe_info), + (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT")); + + + switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) { +case UE_CONTROL: + pipetype = "CONTROL"; + break; + case UE_BULK: + pipetype = "BULK"; + break; + case UE_INTERRUPT: + pipetype = "INTERRUPT"; + break; + case UE_ISOCHRONOUS: + pipetype = "ISOCHRONOUS"; + break; + default: + pipetype = "UNKNOWN"; + break; + } + + DWC_ERROR(" Endpoint type: %s\n", pipetype); + + switch (hc->speed) { + case DWC_OTG_EP_SPEED_HIGH: + speed = "HIGH"; + break; + case DWC_OTG_EP_SPEED_FULL: + speed = "FULL"; + break; + case DWC_OTG_EP_SPEED_LOW: + speed = "LOW"; + break; + default: + speed = "UNKNOWN"; + break; + }; + + DWC_ERROR(" Speed: %s\n", speed); + + DWC_ERROR(" Max packet size: %d\n", + dwc_otg_hcd_get_mps(&urb->pipe_info)); + DWC_ERROR(" Data buffer length: %d\n", urb->length); + DWC_ERROR(" Transfer buffer: %p, Transfer DMA: %p\n", + urb->buf, (void *)urb->dma); + DWC_ERROR(" Setup buffer: %p, Setup DMA: %p\n", + urb->setup_packet, (void *)urb->setup_dma); + DWC_ERROR(" Interval: %d\n", urb->interval); + + /* Core haltes the channel for Descriptor DMA mode */ + if (hcd->core_if->dma_desc_enable) { + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_AHB_ERR); + goto handle_ahberr_done; + } + + hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_IO); + + /* + * Force a channel halt. Don't call halt_channel because that won't + * write to the HCCHARn register in DMA mode to force the halt. + */ + dwc_otg_hc_halt(hcd->core_if, hc, DWC_OTG_HC_XFER_AHB_ERR); +handle_ahberr_done: + disable_hc_int(hc_regs, ahberr); + return 1; +} + +/** + * Handles a host channel transaction error interrupt. This handler may be + * called in either DMA mode or Slave mode. + */ +static int32_t handle_hc_xacterr_intr(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_qtd_t * qtd) +{ + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " + "Transaction Error--\n", hc->hc_num); + + if (hcd->core_if->dma_desc_enable) { + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_XACT_ERR); + goto handle_xacterr_done; + } + + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) { + case UE_CONTROL: + case UE_BULK: + qtd->error_count++; + if (!hc->qh->ping_state) { + + update_urb_state_xfer_intr(hc, hc_regs, + qtd->urb, qtd, + DWC_OTG_HC_XFER_XACT_ERR); + dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); + if (!hc->ep_is_in && hc->speed == DWC_OTG_EP_SPEED_HIGH) { + hc->qh->ping_state = 1; + } + } + + /* + * Halt the channel so the transfer can be re-started from + * the appropriate point or the PING protocol will start. + */ + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR); + break; + case UE_INTERRUPT: + qtd->error_count++; + if (hc->do_split && hc->complete_split) { + qtd->complete_split = 0; + } + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR); + break; + case UE_ISOCHRONOUS: + { + dwc_otg_halt_status_e halt_status; + halt_status = + update_isoc_urb_state(hcd, hc, hc_regs, qtd, + DWC_OTG_HC_XFER_XACT_ERR); + + halt_channel(hcd, hc, qtd, halt_status); + } + break; + } +handle_xacterr_done: + disable_hc_int(hc_regs, xacterr); + + return 1; +} + +/** + * Handles a host channel frame overrun interrupt. This handler may be called + * in either DMA mode or Slave mode. + */ +static int32_t handle_hc_frmovrun_intr(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_qtd_t * qtd) +{ + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " + "Frame Overrun--\n", hc->hc_num); + + switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) { + case UE_CONTROL: + case UE_BULK: + break; + case UE_INTERRUPT: + halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_FRAME_OVERRUN); + break; + case UE_ISOCHRONOUS: + { + dwc_otg_halt_status_e halt_status; + halt_status = + update_isoc_urb_state(hcd, hc, hc_regs, qtd, + DWC_OTG_HC_XFER_FRAME_OVERRUN); + + halt_channel(hcd, hc, qtd, halt_status); + } + break; + } + + disable_hc_int(hc_regs, frmovrun); + + return 1; +} + +/** + * Handles a host channel data toggle error interrupt. This handler may be + * called in either DMA mode or Slave mode. + */ +static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_qtd_t * qtd) +{ + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " + "Data Toggle Error--\n", hc->hc_num); + + if (hc->ep_is_in) { + qtd->error_count = 0; + } else { + DWC_ERROR("Data Toggle Error on OUT transfer," + "channel %d\n", hc->hc_num); + } + + disable_hc_int(hc_regs, datatglerr); + + return 1; +} + +#ifdef DEBUG +/** + * This function is for debug only. It checks that a valid halt status is set + * and that HCCHARn.chdis is clear. If there's a problem, corrective action is + * taken and a warning is issued. + * @return 1 if halt status is ok, 0 otherwise. + */ +static inline int halt_status_ok(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_qtd_t * qtd) +{ + hcchar_data_t hcchar; + hctsiz_data_t hctsiz; + hcint_data_t hcint; + hcintmsk_data_t hcintmsk; + hcsplt_data_t hcsplt; + + if (hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS) { + /* + * This code is here only as a check. This condition should + * never happen. Ignore the halt if it does occur. + */ + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz); + hcint.d32 = dwc_read_reg32(&hc_regs->hcint); + hcintmsk.d32 = dwc_read_reg32(&hc_regs->hcintmsk); + hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt); + DWC_WARN + ("%s: hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS, " + "channel %d, hcchar 0x%08x, hctsiz 0x%08x, " + "hcint 0x%08x, hcintmsk 0x%08x, " + "hcsplt 0x%08x, qtd->complete_split %d\n", __func__, + hc->hc_num, hcchar.d32, hctsiz.d32, hcint.d32, + hcintmsk.d32, hcsplt.d32, qtd->complete_split); + + DWC_WARN("%s: no halt status, channel %d, ignoring interrupt\n", + __func__, hc->hc_num); + DWC_WARN("\n"); + clear_hc_int(hc_regs, chhltd); + return 0; + } + + /* + * This code is here only as a check. hcchar.chdis should + * never be set when the halt interrupt occurs. Halt the + * channel again if it does occur. + */ + hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); + if (hcchar.b.chdis) { + DWC_WARN("%s: hcchar.chdis set unexpectedly, " + "hcchar 0x%08x, trying to halt again\n", + __func__, hcchar.d32); + clear_hc_int(hc_regs, chhltd); + hc->halt_pending = 0; + halt_channel(hcd, hc, qtd, hc->halt_status); + return 0; + } + + return 1; +} +#endif + +/** + * Handles a host Channel Halted interrupt in DMA mode. This handler + * determines the reason the channel halted and proceeds accordingly. + */ +static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_qtd_t * qtd) +{ + hcint_data_t hcint; + hcintmsk_data_t hcintmsk; + int out_nak_enh = 0; + + /* For core with OUT NAK enhancement, the flow for high- + * speed CONTROL/BULK OUT is handled a little differently. + */ + if (hcd->core_if->snpsid >= OTG_CORE_REV_2_71a) { + if (hc->speed == DWC_OTG_EP_SPEED_HIGH && !hc->ep_is_in && + (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL || + hc->ep_type == DWC_OTG_EP_TYPE_BULK)) { + out_nak_enh = 1; + } + } + + if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE || + (hc->halt_status == DWC_OTG_HC_XFER_AHB_ERR && !hcd->core_if->dma_desc_enable)) { + /* + * Just release the channel. A dequeue can happen on a + * transfer timeout. In the case of an AHB Error, the channel + * was forced to halt because there's no way to gracefully + * recover. + */ + if (hcd->core_if->dma_desc_enable) + dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, hc->halt_status); + else + release_channel(hcd, hc, qtd, hc->halt_status); + return; + } + + /* Read the HCINTn register to determine the cause for the halt. */ + hcint.d32 = dwc_read_reg32(&hc_regs->hcint); + hcintmsk.d32 = dwc_read_reg32(&hc_regs->hcintmsk); + + if (hcint.b.xfercomp) { + /** @todo This is here because of a possible hardware bug. Spec + * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT + * interrupt w/ACK bit set should occur, but I only see the + * XFERCOMP bit, even with it masked out. This is a workaround + * for that behavior. Should fix this when hardware is fixed. + */ + if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) { + handle_hc_ack_intr(hcd, hc, hc_regs, qtd); + } + handle_hc_xfercomp_intr(hcd, hc, hc_regs, qtd); + } else if (hcint.b.stall) { + handle_hc_stall_intr(hcd, hc, hc_regs, qtd); + } else if (hcint.b.xacterr && !hcd->core_if->dma_desc_enable) { + if (out_nak_enh) { + if (hcint.b.nyet || hcint.b.nak || hcint.b.ack) { + DWC_DEBUG("XactErr with NYET/NAK/ACK\n"); + qtd->error_count = 0; + } else { + DWC_DEBUG("XactErr without NYET/NAK/ACK\n"); + } + } + + /* + * Must handle xacterr before nak or ack. Could get a xacterr + * at the same time as either of these on a BULK/CONTROL OUT + * that started with a PING. The xacterr takes precedence. + */ + handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd); + } else if (hcint.b.xcs_xact && hcd->core_if->dma_desc_enable) { + handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd); + } else if (hcint.b.ahberr && hcd->core_if->dma_desc_enable) { + handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd); + } else if (hcint.b.bblerr) { + handle_hc_babble_intr(hcd, hc, hc_regs, qtd); + } else if (hcint.b.frmovrun) { + handle_hc_frmovrun_intr(hcd, hc, hc_regs, qtd); + } else if (!out_nak_enh) { + if (hcint.b.nyet) { + /* + * Must handle nyet before nak or ack. Could get a nyet at the + * same time as either of those on a BULK/CONTROL OUT that + * started with a PING. The nyet takes precedence. + */ + handle_hc_nyet_intr(hcd, hc, hc_regs, qtd); + } else if (hcint.b.nak && !hcintmsk.b.nak) { + /* + * If nak is not masked, it's because a non-split IN transfer + * is in an error state. In that case, the nak is handled by + * the nak interrupt handler, not here. Handle nak here for + * BULK/CONTROL OUT transfers, which halt on a NAK to allow + * rewinding the buffer pointer. + */ + handle_hc_nak_intr(hcd, hc, hc_regs, qtd); + } else if (hcint.b.ack && !hcintmsk.b.ack) { + /* + * If ack is not masked, it's because a non-split IN transfer + * is in an error state. In that case, the ack is handled by + * the ack interrupt handler, not here. Handle ack here for + * split transfers. Start splits halt on ACK. + */ + handle_hc_ack_intr(hcd, hc, hc_regs, qtd); + } else { + if (hc->ep_type == DWC_OTG_EP_TYPE_INTR || + hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { + /* + * A periodic transfer halted with no other channel + * interrupts set. Assume it was halted by the core + * because it could not be completed in its scheduled + * (micro)frame. + */ +#ifdef DEBUG + DWC_PRINTF + ("%s: Halt channel %d (assume incomplete periodic transfer)\n", + __func__, hc->hc_num); +#endif + halt_channel(hcd, hc, qtd, + DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE); + } else { + DWC_ERROR + ("%s: Channel %d, DMA Mode -- ChHltd set, but reason " + "for halting is unknown, hcint 0x%08x, intsts 0x%08x\n", + __func__, hc->hc_num, hcint.d32, + dwc_read_reg32(&hcd->core_if-> + core_global_regs->gintsts)); + } + + } + } else { + DWC_PRINTF("NYET/NAK/ACK/other in non-error case, 0x%08x\n", + hcint.d32); + } +} + +/** + * Handles a host channel Channel Halted interrupt. + * + * In slave mode, this handler is called only when the driver specifically + * requests a halt. This occurs during handling other host channel interrupts + * (e.g. nak, xacterr, stall, nyet, etc.). + * + * In DMA mode, this is the interrupt that occurs when the core has finished + * processing a transfer on a channel. Other host channel interrupts (except + * ahberr) are disabled in DMA mode. + */ +static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd, + dwc_hc_t * hc, + dwc_otg_hc_regs_t * hc_regs, + dwc_otg_qtd_t * qtd) +{ + DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " + "Channel Halted--\n", hc->hc_num); + + if (hcd->core_if->dma_enable) { + handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd); + } else { +#ifdef DEBUG + if (!halt_status_ok(hcd, hc, hc_regs, qtd)) { + return 1; + } +#endif + release_channel(hcd, hc, qtd, hc->halt_status); + } + + return 1; +} + +/** Handles interrupt for a specific Host Channel */ +int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) +{ + int retval = 0; + hcint_data_t hcint; + hcintmsk_data_t hcintmsk; + dwc_hc_t *hc; + dwc_otg_hc_regs_t *hc_regs; + dwc_otg_qtd_t *qtd; + + DWC_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", num); + + hc = dwc_otg_hcd->hc_ptr_array[num]; + hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[num]; + qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list); + + hcint.d32 = dwc_read_reg32(&hc_regs->hcint); + hcintmsk.d32 = dwc_read_reg32(&hc_regs->hcintmsk); + DWC_DEBUGPL(DBG_HCDV, + " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n", + hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32)); + hcint.d32 = hcint.d32 & hcintmsk.d32; + + if (!dwc_otg_hcd->core_if->dma_enable) { + if (hcint.b.chhltd && hcint.d32 != 0x2) { + hcint.b.chhltd = 0; + } + } + + if (hcint.b.xfercomp) { + retval |= + handle_hc_xfercomp_intr(dwc_otg_hcd, hc, hc_regs, qtd); + /* + * If NYET occurred at same time as Xfer Complete, the NYET is + * handled by the Xfer Complete interrupt handler. Don't want + * to call the NYET interrupt handler in this case. + */ + hcint.b.nyet = 0; + } + if (hcint.b.chhltd) { + retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd); + } + if (hcint.b.ahberr) { + retval |= handle_hc_ahberr_intr(dwc_otg_hcd, hc, hc_regs, qtd); + } + if (hcint.b.stall) { + retval |= handle_hc_stall_intr(dwc_otg_hcd, hc, hc_regs, qtd); + } + if (hcint.b.nak) { + retval |= handle_hc_nak_intr(dwc_otg_hcd, hc, hc_regs, qtd); + } + if (hcint.b.ack) { + retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd); + } + if (hcint.b.nyet) { + retval |= handle_hc_nyet_intr(dwc_otg_hcd, hc, hc_regs, qtd); + } + if (hcint.b.xacterr) { + retval |= handle_hc_xacterr_intr(dwc_otg_hcd, hc, hc_regs, qtd); + } + if (hcint.b.bblerr) { + retval |= handle_hc_babble_intr(dwc_otg_hcd, hc, hc_regs, qtd); + } + if (hcint.b.frmovrun) { + retval |= + handle_hc_frmovrun_intr(dwc_otg_hcd, hc, hc_regs, qtd); + } + if (hcint.b.datatglerr) { + retval |= + handle_hc_datatglerr_intr(dwc_otg_hcd, hc, hc_regs, qtd); + } + + return retval; +} + +#endif /* DWC_DEVICE_ONLY */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c new file mode 100644 index 000000000000..a5f8546ea7dd --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c @@ -0,0 +1,840 @@ +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_linux.c $ + * $Revision: #11 $ + * $Date: 2009/04/21 $ + * $Change: 1237476 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ +#ifndef DWC_DEVICE_ONLY + +/** + * @file + * + * This file contains the implementation of the HCD. In Linux, the HCD + * implements the hc_driver API. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef LM_INTERFACE +//#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) +#include +#include +#else +#include +#include +#endif +#elif defined(PLATFORM_INTERFACE) +#include +#endif + +#include +#include + +#include "dwc_otg_hcd_if.h" +#include "dwc_otg_dbg.h" +#include "dwc_otg_driver.h" + +/** + * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is + * qualified with its direction (possible 32 endpoints per device). + */ +#define dwc_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \ + ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4) + +static const char dwc_otg_hcd_name[] = "dwc_otg_hcd"; + +/** @name Linux HC Driver API Functions */ +/** @{ */ +/* manage i/o requests, device state */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) +static int urb_enqueue(struct usb_hcd *hcd, + struct usb_host_endpoint *ep, + struct urb *urb, gfp_t mem_flags); + +static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb); +#else +static int urb_enqueue(struct usb_hcd *hcd, + struct urb *urb, gfp_t mem_flags); + +static int urb_dequeue(struct usb_hcd *hcd, + struct urb *urb, int status); +#endif + +static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep); + +static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd); +extern int hcd_start(struct usb_hcd *hcd); +extern void hcd_stop(struct usb_hcd *hcd); +static int get_frame_number(struct usb_hcd *hcd); +extern int hub_status_data(struct usb_hcd *hcd, char *buf); +extern int hub_control(struct usb_hcd *hcd, + u16 typeReq, + u16 wValue, u16 wIndex, char *buf, u16 wLength); + +struct wrapper_priv_data { + dwc_otg_hcd_t *dwc_otg_hcd; +}; + +/** @} */ + +static struct hc_driver dwc_otg_hc_driver = { + + .description = dwc_otg_hcd_name, + .product_desc = "DWC OTG Controller", + .hcd_priv_size = sizeof(struct wrapper_priv_data), + + .irq = dwc_otg_hcd_irq, + + .flags = HCD_MEMORY | HCD_USB2, + + //.reset = + .start = hcd_start, + //.suspend = + //.resume = + .stop = hcd_stop, + + .urb_enqueue = urb_enqueue, + .urb_dequeue = urb_dequeue, + .endpoint_disable = endpoint_disable, + + .get_frame_number = get_frame_number, + + .hub_status_data = hub_status_data, + .hub_control = hub_control, + //.bus_suspend = + //.bus_resume = +}; + +/** Gets the dwc_otg_hcd from a struct usb_hcd */ +static inline dwc_otg_hcd_t *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd) +{ + struct wrapper_priv_data *p; + p = (struct wrapper_priv_data *)(hcd->hcd_priv); + return p->dwc_otg_hcd; +} + +/** Gets the struct usb_hcd that contains a dwc_otg_hcd_t. */ +static inline struct usb_hcd *dwc_otg_hcd_to_hcd(dwc_otg_hcd_t * dwc_otg_hcd) +{ + return dwc_otg_hcd_get_priv_data(dwc_otg_hcd); +} + +/** Gets the usb_host_endpoint associated with an URB. */ +inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb *urb) +{ + struct usb_device *dev = urb->dev; + int ep_num = usb_pipeendpoint(urb->pipe); + + if (usb_pipein(urb->pipe)) + return dev->ep_in[ep_num]; + else + return dev->ep_out[ep_num]; +} + +static int _disconnect(dwc_otg_hcd_t * hcd) +{ + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd); + + usb_hcd->self.is_b_host = 0; + return 0; +} + +static int _start(dwc_otg_hcd_t * hcd) +{ + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd); + + usb_hcd->self.is_b_host = dwc_otg_hcd_is_b_host(hcd); + hcd_start(usb_hcd); + + return 0; +} + +static int _hub_info(dwc_otg_hcd_t * hcd, void *urb_handle, uint32_t * hub_addr, + uint32_t * port_addr) +{ + struct urb *urb = (struct urb *)urb_handle; +#if 1 //GRAYG - temporary + if (NULL == urb_handle) + DWC_ERROR("**** %s - NULL URB handle\n", __func__);//GRAYG + if (NULL == urb->dev) + DWC_ERROR("**** %s - URB has no device\n", __func__);//GRAYG + if (NULL == port_addr) + DWC_ERROR("**** %s - NULL port_address\n", __func__);//GRAYG +#endif + if (urb->dev->tt) { + if (NULL == urb->dev->tt->hub) { + DWC_ERROR("**** %s - (URB's transactor has no TT - giving no hub)\n", + __func__); //GRAYG + //*hub_addr = (u8)usb_pipedevice(urb->pipe); //GRAYG + *hub_addr = 0; //GRAYG + // we probably shouldn't have a transaction translator if + // there's no associated hub? + } else + *hub_addr = urb->dev->tt->hub->devnum; + } else { + *hub_addr = 0; + } + *port_addr = urb->dev->ttport; + return 0; +} + +static int _speed(dwc_otg_hcd_t * hcd, void *urb_handle) +{ + struct urb *urb = (struct urb *)urb_handle; + return urb->dev->speed; +} + +static int _get_b_hnp_enable(dwc_otg_hcd_t * hcd) +{ + struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd); + return usb_hcd->self.b_hnp_enable; +} + +static void allocate_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw, + struct urb *urb) +{ + hcd_to_bus(hcd)->bandwidth_allocated += bw / urb->interval; + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + hcd_to_bus(hcd)->bandwidth_isoc_reqs++; + } else { + hcd_to_bus(hcd)->bandwidth_int_reqs++; + } +} + +static void free_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw, + struct urb *urb) +{ + hcd_to_bus(hcd)->bandwidth_allocated -= bw / urb->interval; + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + hcd_to_bus(hcd)->bandwidth_isoc_reqs--; + } else { + hcd_to_bus(hcd)->bandwidth_int_reqs--; + } +} + +/** + * Sets the final status of an URB and returns it to the device driver. Any + * required cleanup of the URB is performed. + */ +static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle, + dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status) +{ + struct urb *urb = (struct urb *)urb_handle; +#ifdef DEBUG + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { + DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n", + __func__, urb, usb_pipedevice(urb->pipe), + usb_pipeendpoint(urb->pipe), + usb_pipein(urb->pipe) ? "IN" : "OUT", status); + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + int i; + for (i = 0; i < urb->number_of_packets; i++) { + DWC_PRINTF(" ISO Desc %d status: %d\n", + i, urb->iso_frame_desc[i].status); + } + } + } +#endif + + urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb); + /* Convert status value. */ + switch (status) { + case -DWC_E_PROTOCOL: + status = -EPROTO; + break; + case -DWC_E_IN_PROGRESS: + status = -EINPROGRESS; + break; + case -DWC_E_PIPE: + status = -EPIPE; + break; + case -DWC_E_IO: + status = -EIO; + break; + case -DWC_E_TIMEOUT: + status = -ETIMEDOUT; + break; + case -DWC_E_OVERFLOW: + status = -EOVERFLOW; + break; + default: + if (status) { + DWC_PRINTF("Uknown urb status %d\n", status); + + } + } + + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + int i; + + urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb); + for (i = 0; i < urb->number_of_packets; ++i) { + urb->iso_frame_desc[i].actual_length = + dwc_otg_hcd_urb_get_iso_desc_actual_length + (dwc_otg_urb, i); + urb->iso_frame_desc[i].status = + dwc_otg_hcd_urb_get_iso_desc_status + (dwc_otg_urb, i); + } + } + + urb->status = status; + urb->hcpriv = NULL; + if (!status) { + if ((urb->transfer_flags & URB_SHORT_NOT_OK) && + (urb->actual_length < urb->transfer_buffer_length)) { + urb->status = -EREMOTEIO; + } + } + + if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) || + (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) { + struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb); + if (ep) { + free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd), + dwc_otg_hcd_get_ep_bandwidth(hcd, + ep-> + hcpriv), + urb); + } + } + + dwc_free(dwc_otg_urb); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) + usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb); +#else + usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb); + usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, status); +#endif + return 0; +} + +static struct dwc_otg_hcd_function_ops hcd_fops = { + .start = _start, + .disconnect = _disconnect, + .hub_info = _hub_info, + .speed = _speed, + .complete = _complete, + .get_b_hnp_enable = _get_b_hnp_enable, +}; + +/** + * Initializes the HCD. This function allocates memory for and initializes the + * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the + * USB bus with the core and calls the hc_driver->start() function. It returns + * a negative error on failure. + */ +int hcd_init( +#ifdef LM_INTERFACE + struct lm_device *_dev +#elif defined(PCI_INTERFACE) + struct pci_dev *_dev +#elif defined(PLATFORM_INTERFACE) + struct platform_device *_dev +#endif + ) +{ + struct usb_hcd *hcd = NULL; + dwc_otg_hcd_t *dwc_otg_hcd = NULL; +#ifdef LM_INTERFACE + dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev); +#endif + + int retval = 0; + u64 dmamask; + + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT otg_dev=%p\n", otg_dev); + + /* Set device flags indicating whether the HCD supports DMA. */ + if (dwc_otg_is_dma_enable(otg_dev->core_if)) + dmamask = DMA_BIT_MASK(32); + else + dmamask = 0; + +#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE) + dma_set_mask(&_dev->dev, dmamask); + dma_set_coherent_mask(&_dev->dev, dmamask); +#elif defined(PCI_INTERFACE) + pci_set_dma_mask(_dev, dmamask); + pci_set_consistent_dma_mask(_dev, dmamask); +#endif + + /* + * Allocate memory for the base HCD plus the DWC OTG HCD. + * Initialize the base HCD. + */ + hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) + _dev->dev.bus_id); +#else + dev_name(&_dev->dev)); +#endif + if (!hcd) { + retval = -ENOMEM; + goto error1; + } + + hcd->regs = otg_dev->base; + + /* Initialize the DWC OTG HCD. */ + dwc_otg_hcd = dwc_otg_hcd_alloc_hcd(); + if (!dwc_otg_hcd) { + goto error2; + } + ((struct wrapper_priv_data *)(hcd->hcd_priv))->dwc_otg_hcd = + dwc_otg_hcd; + otg_dev->hcd = dwc_otg_hcd; + + if (dwc_otg_hcd_init(dwc_otg_hcd, otg_dev->core_if)) { + goto error2; + } + + hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd); + + /* + * Finish generic HCD initialization and start the HCD. This function + * allocates the DMA buffer pool, registers the USB bus, requests the + * IRQ line, and calls hcd_start method. + */ +#ifdef PLATFORM_INTERFACE + retval = usb_add_hcd(hcd, platform_get_irq(_dev, 0), IRQF_SHARED); +#else + retval = usb_add_hcd(hcd, _dev->irq, IRQF_SHARED); +#endif + if (retval < 0) { + goto error2; + } + + dwc_otg_hcd_set_priv_data(dwc_otg_hcd, hcd); + return 0; + + error2: + usb_put_hcd(hcd); + error1: + return retval; +} + +/** + * Removes the HCD. + * Frees memory and resources associated with the HCD and deregisters the bus. + */ +void hcd_remove( +#ifdef LM_INTERFACE + struct lm_device *_dev +#elif defined(PCI_INTERFACE) + struct pci_dev *_dev +#elif defined(PLATFORM_INTERFACE) + struct platform_device *_dev +#endif + ) +{ +#ifdef LM_INTERFACE + dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev); +#endif + + dwc_otg_hcd_t *dwc_otg_hcd; + struct usb_hcd *hcd; + + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE otg_dev=%p\n", otg_dev); + + if (!otg_dev) { + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__); + return; + } + + dwc_otg_hcd = otg_dev->hcd; + + if (!dwc_otg_hcd) { + DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__); + return; + } + + hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd); + + if (!hcd) { + DWC_DEBUGPL(DBG_ANY, + "%s: dwc_otg_hcd_to_hcd(dwc_otg_hcd) NULL!\n", + __func__); + return; + } + usb_remove_hcd(hcd); + dwc_otg_hcd_set_priv_data(dwc_otg_hcd, NULL); + dwc_otg_hcd_remove(dwc_otg_hcd); + usb_put_hcd(hcd); +} + +/* ========================================================================= + * Linux HC Driver Functions + * ========================================================================= */ + +/** Initializes the DWC_otg controller and its root hub and prepares it for host + * mode operation. Activates the root port. Returns 0 on success and a negative + * error code on failure. */ +int hcd_start(struct usb_hcd *hcd) +{ + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); + struct usb_bus *bus; + + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n"); + bus = hcd_to_bus(hcd); + + hcd->state = HC_STATE_RUNNING; + if (dwc_otg_hcd_start(dwc_otg_hcd, &hcd_fops)) { + return 0; + } + + /* Initialize and connect root hub if one is not already attached */ + if (bus->root_hub) { + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n"); + /* Inform the HUB driver to resume. */ + usb_hcd_resume_root_hub(hcd); + } + + return 0; +} + +/** + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are + * stopped. + */ +void hcd_stop(struct usb_hcd *hcd) +{ + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); + + dwc_otg_hcd_stop(dwc_otg_hcd); +} + +/** Returns the current frame number. */ +static int get_frame_number(struct usb_hcd *hcd) +{ + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); + + return dwc_otg_hcd_get_frame_number(dwc_otg_hcd); +} + +#ifdef DEBUG +static void dump_urb_info(struct urb *urb, char *fn_name) +{ + DWC_PRINTF("%s, urb %p\n", fn_name, urb); + DWC_PRINTF(" Device address: %d\n", usb_pipedevice(urb->pipe)); + DWC_PRINTF(" Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe), + (usb_pipein(urb->pipe) ? "IN" : "OUT")); + DWC_PRINTF(" Endpoint type: %s\n", ( { + char *pipetype; + switch (usb_pipetype(urb->pipe)) { +case PIPE_CONTROL: +pipetype = "CONTROL"; break; case PIPE_BULK: +pipetype = "BULK"; break; case PIPE_INTERRUPT: +pipetype = "INTERRUPT"; break; case PIPE_ISOCHRONOUS: +pipetype = "ISOCHRONOUS"; break; default: + pipetype = "UNKNOWN"; break;}; + pipetype;} + )) ; + DWC_PRINTF(" Speed: %s\n", ( { + char *speed; switch (urb->dev->speed) { +case USB_SPEED_HIGH: +speed = "HIGH"; break; case USB_SPEED_FULL: +speed = "FULL"; break; case USB_SPEED_LOW: +speed = "LOW"; break; default: + speed = "UNKNOWN"; break;}; + speed;} + )) ; + DWC_PRINTF(" Max packet size: %d\n", + usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))); + DWC_PRINTF(" Data buffer length: %d\n", urb->transfer_buffer_length); + DWC_PRINTF(" Transfer buffer: %p, Transfer DMA: %p\n", + urb->transfer_buffer, (void *)urb->transfer_dma); + DWC_PRINTF(" Setup buffer: %p, Setup DMA: %p\n", + urb->setup_packet, (void *)urb->setup_dma); + DWC_PRINTF(" Interval: %d\n", urb->interval); + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + int i; + for (i = 0; i < urb->number_of_packets; i++) { + DWC_PRINTF(" ISO Desc %d:\n", i); + DWC_PRINTF(" offset: %d, length %d\n", + urb->iso_frame_desc[i].offset, + urb->iso_frame_desc[i].length); + } + } +} + +#endif + +/** Starts processing a USB transfer request specified by a USB Request Block + * (URB). mem_flags indicates the type of memory allocation to use while + * processing this URB. */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) +static int urb_enqueue(struct usb_hcd *hcd, + struct usb_host_endpoint *ep, + struct urb *urb, gfp_t mem_flags) +{ +#else +static int urb_enqueue(struct usb_hcd *hcd, + struct urb *urb, + gfp_t mem_flags) +{ + struct usb_host_endpoint *ep = urb->ep; +#endif + void **ref_ep_hcpriv = &ep->hcpriv; + int retval = 0; + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); + dwc_otg_hcd_urb_t *dwc_otg_urb; + int i; + int alloc_bandwidth = 0; + uint8_t ep_type = 0; + uint32_t flags = 0; + void *buf; + +#ifdef DEBUG + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { + dump_urb_info(urb, "urb_enqueue"); + } +#endif + + if (!urb->transfer_buffer && urb->transfer_buffer_length) + return -EINVAL; + + if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) + || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) { + if (!dwc_otg_hcd_is_bandwidth_allocated + (dwc_otg_hcd, ref_ep_hcpriv)) { + alloc_bandwidth = 1; + } + } + + switch (usb_pipetype(urb->pipe)) { + case PIPE_CONTROL: + ep_type = USB_ENDPOINT_XFER_CONTROL; + break; + case PIPE_ISOCHRONOUS: + ep_type = USB_ENDPOINT_XFER_ISOC; + break; + case PIPE_BULK: + ep_type = USB_ENDPOINT_XFER_BULK; + break; + case PIPE_INTERRUPT: + ep_type = USB_ENDPOINT_XFER_INT; + break; + default: + DWC_WARN("Wrong ep type\n"); + } + + dwc_otg_urb = dwc_otg_hcd_urb_alloc(dwc_otg_hcd, + urb->number_of_packets, + mem_flags == GFP_ATOMIC ? 1 : 0); + + urb->hcpriv = dwc_otg_urb; + + dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe), + usb_pipeendpoint(urb->pipe), ep_type, + usb_pipein(urb->pipe), + usb_maxpacket(urb->dev, urb->pipe, + !(usb_pipein(urb->pipe)))); + + buf = urb->transfer_buffer; + if (hcd->self.uses_dma) { + /* + * Calculate virtual address from physical address, + * because some class driver may not fill transfer_buffer. + * In Buffer DMA mode virual address is used, + * when handling non DWORD aligned buffers. + */ + //buf = phys_to_virt(urb->transfer_dma); + // DMA addresses are bus addresses not physical addresses! + buf = dma_to_virt(&urb->dev->dev, urb->transfer_dma); + } + + if (!(urb->transfer_flags & URB_NO_INTERRUPT)) + flags |= URB_GIVEBACK_ASAP; + if (urb->transfer_flags & URB_ZERO_PACKET) + flags |= URB_SEND_ZERO_PACKET; + + dwc_otg_hcd_urb_set_params(dwc_otg_urb, urb, buf, + urb->transfer_dma, + urb->transfer_buffer_length, + urb->setup_packet, + urb->setup_dma, + flags, + urb->interval); + + for (i = 0; i < urb->number_of_packets; ++i) { + dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_urb, i, + urb->iso_frame_desc[i]. + offset, + urb->iso_frame_desc[i]. + length); + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)) + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (0 == retval) +#endif + { + retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb, + /*(dwc_otg_qh_t **)*/ + ref_ep_hcpriv); + if (0 == retval) { + if (alloc_bandwidth) { + allocate_bus_bandwidth(hcd, + dwc_otg_hcd_get_ep_bandwidth( + dwc_otg_hcd, *ref_ep_hcpriv), + urb); + } + } else { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)) + usb_hcd_unlink_urb_from_ep(hcd, urb); +#endif + if (retval == -DWC_E_NO_DEVICE) { + retval = -ENODEV; + } + } + } + return retval; +} + +/** Aborts/cancels a USB transfer request. Always returns 0 to indicate + * success. */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) +static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +#else +static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) +#endif +{ + dwc_otg_hcd_t *dwc_otg_hcd; + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n"); + + dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); + +#ifdef DEBUG + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { + dump_urb_info(urb, "urb_dequeue"); + } +#endif + dwc_otg_hcd_urb_dequeue(dwc_otg_hcd, (dwc_otg_hcd_urb_t *)urb->hcpriv); + + dwc_free(urb->hcpriv); + urb->hcpriv = NULL; + + /* Higher layer software sets URB status. */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) + usb_hcd_giveback_urb(hcd, urb); +#else + usb_hcd_unlink_urb_from_ep(hcd, urb); + usb_hcd_giveback_urb(hcd, urb, status); +#endif + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { + DWC_PRINTF("Called usb_hcd_giveback_urb()\n"); + DWC_PRINTF(" urb->status = %d\n", urb->status); + } + + return 0; +} + +/* Frees resources in the DWC_otg controller related to a given endpoint. Also + * clears state in the HCD related to the endpoint. Any URBs for the endpoint + * must already be dequeued. */ +static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep) +{ + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); + + DWC_DEBUGPL(DBG_HCD, + "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, " + "endpoint=%d\n", ep->desc.bEndpointAddress, + dwc_ep_addr_to_endpoint(ep->desc.bEndpointAddress)); + dwc_otg_hcd_endpoint_disable(dwc_otg_hcd, ep->hcpriv, 250); + ep->hcpriv = NULL; +} + +/** Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if + * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid + * interrupt. + * + * This function is called by the USB core when an interrupt occurs */ +static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd) +{ + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); + int32_t retval = dwc_otg_hcd_handle_intr(dwc_otg_hcd); + if (retval != 0) { + S3C2410X_CLEAR_EINTPEND(); + } + return IRQ_RETVAL(retval); +} + +/** Creates Status Change bitmap for the root hub and root port. The bitmap is + * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1 + * is the status change indicator for the single root port. Returns 1 if either + * change indicator is 1, otherwise returns 0. */ +int hub_status_data(struct usb_hcd *hcd, char *buf) +{ + dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); + + buf[0] = 0; + buf[0] |= (dwc_otg_hcd_is_status_changed(dwc_otg_hcd, 1)) << 1; + + return (buf[0] != 0); +} + +/** Handles hub class-specific requests. */ +int hub_control(struct usb_hcd *hcd, + u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) +{ + int retval; + + retval = dwc_otg_hcd_hub_control(hcd_to_dwc_otg_hcd(hcd), + typeReq, wValue, wIndex, buf, wLength); + + switch (retval) { + case -DWC_E_INVALID: + retval = -EINVAL; + break; + } + + return retval; +} + +#endif /* DWC_DEVICE_ONLY */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c new file mode 100644 index 000000000000..cfed8070dc5c --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c @@ -0,0 +1,732 @@ +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_queue.c $ + * $Revision: #39 $ + * $Date: 2009/04/21 $ + * $Change: 1237477 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ +#ifndef DWC_DEVICE_ONLY + +/** + * @file + * + * This file contains the functions to manage Queue Heads and Queue + * Transfer Descriptors. + */ + +#include "dwc_otg_hcd.h" +#include "dwc_otg_regs.h" + +/** + * Free each QTD in the QH's QTD-list then free the QH. QH should already be + * removed from a list. QTD list should already be empty if called from URB + * Dequeue. + * + * @param hcd HCD instance. + * @param qh The QH to free. + */ +void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) +{ + dwc_otg_qtd_t *qtd, *qtd_tmp; + uint64_t flags; + + /* Free each QTD in the QTD list */ + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); + DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) { + DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry); + dwc_otg_hcd_qtd_free(qtd); + } + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); + + if (hcd->core_if->dma_desc_enable) { + dwc_otg_hcd_qh_free_ddma(hcd, qh); + } + else if (qh->dw_align_buf) { + uint32_t buf_size; + if(qh->ep_type == UE_ISOCHRONOUS) { + buf_size = 4096; + } else { + buf_size = hcd->core_if->core_params->max_transfer_size; + } + dwc_dma_free(buf_size, qh->dw_align_buf, qh->dw_align_buf_dma); + } + + + + dwc_free(qh); + return; +} + +#define BitStuffTime(bytecount) ((8 * 7* bytecount) / 6) +#define HS_HOST_DELAY 5 /* nanoseconds */ +#define FS_LS_HOST_DELAY 1000 /* nanoseconds */ +#define HUB_LS_SETUP 333 /* nanoseconds */ +#define NS_TO_US(ns) ((ns + 500) / 1000) + /* convert & round nanoseconds to microseconds */ + +static uint32_t calc_bus_time(int speed, int is_in, int is_isoc, + int bytecount) +{ + unsigned long retval; + + switch (speed) { + case USB_SPEED_HIGH: + if (is_isoc) { + retval = + ((38 * 8 * 2083) + + (2083 * (3 + BitStuffTime(bytecount)))) / 1000 + + HS_HOST_DELAY; + } else { + retval = + ((55 * 8 * 2083) + + (2083 * (3 + BitStuffTime(bytecount)))) / 1000 + + HS_HOST_DELAY; + } + break; + case USB_SPEED_FULL: + if (is_isoc) { + retval = + (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000; + if (is_in) { + retval = 7268 + FS_LS_HOST_DELAY + retval; + } else { + retval = 6265 + FS_LS_HOST_DELAY + retval; + } + } else { + retval = + (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000; + retval = 9107 + FS_LS_HOST_DELAY + retval; + } + break; + case USB_SPEED_LOW: + if (is_in) { + retval = + (67667 * (31 + 10 * BitStuffTime(bytecount))) / + 1000; + retval = + 64060 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY + + retval; + } else { + retval = + (66700 * (31 + 10 * BitStuffTime(bytecount))) / + 1000; + retval = + 64107 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY + + retval; + } + break; + default: + DWC_WARN("Unknown device speed\n"); + retval = -1; + } + + return NS_TO_US(retval); +} + +/** + * Initializes a QH structure. + * + * @param hcd The HCD state structure for the DWC OTG controller. + * @param qh The QH to init. + * @param urb Holds the information about the device/endpoint that we need + * to initialize the QH. + */ +#define SCHEDULE_SLOP 10 +void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, + dwc_otg_hcd_urb_t * urb) +{ + char *speed, *type; + int dev_speed; + uint32_t hub_addr, hub_port; + + dwc_memset(qh, 0, sizeof(dwc_otg_qh_t)); + + /* Initialize QH */ + qh->ep_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info); + + qh->ep_is_in = dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0; + + qh->data_toggle = DWC_OTG_HC_PID_DATA0; + qh->maxp = dwc_otg_hcd_get_mps(&urb->pipe_info); + DWC_CIRCLEQ_INIT(&qh->qtd_list); + DWC_LIST_INIT(&qh->qh_list_entry); + qh->channel = NULL; + + /* FS/LS Enpoint on HS Hub + * NOT virtual root hub */ + dev_speed = hcd->fops->speed(hcd, urb->priv); + hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &hub_port); + qh->do_split = 0; + if (((dev_speed == USB_SPEED_LOW) || + (dev_speed == USB_SPEED_FULL)) && + (hub_addr != 0 && hub_addr != 1)) { + + DWC_DEBUGPL(DBG_HCD, + "QH init: EP %d: TT found at hub addr %d, for port %d\n", + dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr, + hub_port); + + qh->do_split = 1; + } + + if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) { + /* Compute scheduling parameters once and save them. */ + hprt0_data_t hprt; + + /** @todo Account for split transfers in the bus time. */ + int bytecount = + dwc_hb_mult(qh->maxp) * dwc_max_packet(qh->maxp); + + qh->usecs = calc_bus_time((qh->do_split ? USB_SPEED_HIGH : dev_speed), + qh->ep_is_in, + (qh->ep_type == UE_ISOCHRONOUS), + bytecount); + /* Start in a slightly future (micro)frame. */ + qh->sched_frame = dwc_frame_num_inc(hcd->frame_number, + SCHEDULE_SLOP); + qh->interval = urb->interval; + +#if 0 + /* Increase interrupt polling rate for debugging. */ + if (qh->ep_type == UE_INTERRUPT) { + qh->interval = 8; + } +#endif + hprt.d32 = dwc_read_reg32(hcd->core_if->host_if->hprt0); + if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) && + ((dev_speed == USB_SPEED_LOW) || + (dev_speed == USB_SPEED_FULL))) { + qh->interval *= 8; + qh->sched_frame |= 0x7; + qh->start_split_frame = qh->sched_frame; + } + + } + + DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n"); + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - qh = %p\n", qh); + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Device Address = %d\n", + dwc_otg_hcd_get_dev_addr(&urb->pipe_info)); + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Endpoint %d, %s\n", + dwc_otg_hcd_get_ep_num(&urb->pipe_info), + dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT"); + switch (dev_speed) { + case USB_SPEED_LOW: + qh->dev_speed = DWC_OTG_EP_SPEED_LOW; + speed = "low"; + break; + case USB_SPEED_FULL: + qh->dev_speed = DWC_OTG_EP_SPEED_FULL; + speed = "full"; + break; + case USB_SPEED_HIGH: + qh->dev_speed = DWC_OTG_EP_SPEED_HIGH; + speed = "high"; + break; + default: + speed = "?"; + break; + } + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Speed = %s\n", speed); + + switch (qh->ep_type) { + case UE_ISOCHRONOUS: + type = "isochronous"; + break; + case UE_INTERRUPT: + type = "interrupt"; + break; + case UE_CONTROL: + type = "control"; + break; + case UE_BULK: + type = "bulk"; + break; + default: + type = "?"; + break; + } + + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Type = %s\n", type); + +#ifdef DEBUG + if (qh->ep_type == UE_INTERRUPT) { + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n", + qh->usecs); + DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n", + qh->interval); + } +#endif + +} + +/** + * This function allocates and initializes a QH. + * + * @param hcd The HCD state structure for the DWC OTG controller. + * @param urb Holds the information about the device/endpoint that we need + * to initialize the QH. + * + * @return Returns pointer to the newly allocated QH, or NULL on error. */ +dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd, + dwc_otg_hcd_urb_t * urb) +{ + dwc_otg_qh_t *qh; + + /* Allocate memory */ + /** @todo add memflags argument */ + qh = dwc_otg_hcd_qh_alloc(); + if (qh == NULL) { + return NULL; + } + + qh_init(hcd, qh, urb); + + if (hcd->core_if->dma_desc_enable && (dwc_otg_hcd_qh_init_ddma(hcd, qh) < 0)) { + dwc_otg_hcd_qh_free(hcd, qh); + return NULL; + } + + return qh; +} + +/** + * Checks that a channel is available for a periodic transfer. + * + * @return 0 if successful, negative error code otherise. + */ +static int periodic_channel_available(dwc_otg_hcd_t * hcd) +{ + /* + * Currently assuming that there is a dedicated host channnel for each + * periodic transaction plus at least one host channel for + * non-periodic transactions. + */ + int status; + int num_channels; + + num_channels = hcd->core_if->core_params->host_channels; + if ((hcd->periodic_channels + hcd->non_periodic_channels < num_channels) && + (hcd->periodic_channels < num_channels - 1)) { + status = 0; + } else { + DWC_INFO("%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n", + __func__, num_channels, hcd->periodic_channels, hcd->non_periodic_channels); //NOTICE + status = -DWC_E_NO_SPACE; + } + + return status; +} + +/** + * Checks that there is sufficient bandwidth for the specified QH in the + * periodic schedule. For simplicity, this calculation assumes that all the + * transfers in the periodic schedule may occur in the same (micro)frame. + * + * @param hcd The HCD state structure for the DWC OTG controller. + * @param qh QH containing periodic bandwidth required. + * + * @return 0 if successful, negative error code otherwise. + */ +static int check_periodic_bandwidth(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) +{ + int status; + int16_t max_claimed_usecs; + + status = 0; + + if ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) || qh->do_split) { + /* + * High speed mode. + * Max periodic usecs is 80% x 125 usec = 100 usec. + */ + + max_claimed_usecs = 100 - qh->usecs; + } else { + /* + * Full speed mode. + * Max periodic usecs is 90% x 1000 usec = 900 usec. + */ + max_claimed_usecs = 900 - qh->usecs; + } + + if (hcd->periodic_usecs > max_claimed_usecs) { + DWC_INFO("%s: already claimed usecs %d, required usecs %d\n", __func__, hcd->periodic_usecs, qh->usecs); //NOTICE + status = -DWC_E_NO_SPACE; + } + + return status; +} + +/** + * Checks that the max transfer size allowed in a host channel is large enough + * to handle the maximum data transfer in a single (micro)frame for a periodic + * transfer. + * + * @param hcd The HCD state structure for the DWC OTG controller. + * @param qh QH for a periodic endpoint. + * + * @return 0 if successful, negative error code otherwise. + */ +static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) +{ + int status; + uint32_t max_xfer_size; + uint32_t max_channel_xfer_size; + + status = 0; + + max_xfer_size = dwc_max_packet(qh->maxp) * dwc_hb_mult(qh->maxp); + max_channel_xfer_size = hcd->core_if->core_params->max_transfer_size; + + if (max_xfer_size > max_channel_xfer_size) { + DWC_INFO("%s: Periodic xfer length %d > " "max xfer length for channel %d\n", + __func__, max_xfer_size, max_channel_xfer_size); //NOTICE + status = -DWC_E_NO_SPACE; + } + + return status; +} + +/** + * Schedules an interrupt or isochronous transfer in the periodic schedule. + * + * @param hcd The HCD state structure for the DWC OTG controller. + * @param qh QH for the periodic transfer. The QH should already contain the + * scheduling information. + * + * @return 0 if successful, negative error code otherwise. + */ +static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) +{ + int status = 0; + + status = periodic_channel_available(hcd); + if (status) { + DWC_INFO("%s: No host channel available for periodic " "transfer.\n", __func__); //NOTICE + return status; + } + + status = check_periodic_bandwidth(hcd, qh); + if (status) { + DWC_INFO("%s: Insufficient periodic bandwidth for " "periodic transfer.\n", __func__); //NOTICE + return status; + } + + status = check_max_xfer_size(hcd, qh); + if (status) { + DWC_INFO("%s: Channel max transfer size too small " "for periodic transfer.\n", __func__); //NOTICE + return status; + } + + if (hcd->core_if->dma_desc_enable) { + /* Don't rely on SOF and start in ready schedule */ + DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry); + } + else { + /* Always start in the inactive schedule. */ + DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry); + } + + /* Reserve the periodic channel. */ + hcd->periodic_channels++; + + /* Update claimed usecs per (micro)frame. */ + hcd->periodic_usecs += qh->usecs; + + return status; +} + +/** + * This function adds a QH to either the non periodic or periodic schedule if + * it is not already in the schedule. If the QH is already in the schedule, no + * action is taken. + * + * @return 0 if successful, negative error code otherwise. + */ +int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) +{ + int status = 0; + uint64_t flags; + + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); + + if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) { + /* QH already in a schedule. */ + goto done; + } + + /* Add the new QH to the appropriate schedule */ + if (dwc_qh_is_non_per(qh)) { + /* Always start in the inactive schedule. */ + DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive, + &qh->qh_list_entry); + } else { + status = schedule_periodic(hcd, qh); + } + + done: + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); + + return status; +} + +/** + * Removes an interrupt or isochronous transfer from the periodic schedule. + * + * @param hcd The HCD state structure for the DWC OTG controller. + * @param qh QH for the periodic transfer. + */ +static void deschedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) +{ + DWC_LIST_REMOVE_INIT(&qh->qh_list_entry); + + /* Release the periodic channel reservation. */ + hcd->periodic_channels--; + + /* Update claimed usecs per (micro)frame. */ + hcd->periodic_usecs -= qh->usecs; +} + +/** + * Removes a QH from either the non-periodic or periodic schedule. Memory is + * not freed. + * + * @param hcd The HCD state structure. + * @param qh QH to remove from schedule. */ +void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) +{ + uint64_t flags; + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); + + if (DWC_LIST_EMPTY(&qh->qh_list_entry)) { + /* QH is not in a schedule. */ + goto done; + } + + if (dwc_qh_is_non_per(qh)) { + if (hcd->non_periodic_qh_ptr == &qh->qh_list_entry) { + hcd->non_periodic_qh_ptr = + hcd->non_periodic_qh_ptr->next; + } + DWC_LIST_REMOVE_INIT(&qh->qh_list_entry); + } else { + deschedule_periodic(hcd, qh); + } + + done: + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); +} + +/** + * Deactivates a QH. For non-periodic QHs, removes the QH from the active + * non-periodic schedule. The QH is added to the inactive non-periodic + * schedule if any QTDs are still attached to the QH. + * + * For periodic QHs, the QH is removed from the periodic queued schedule. If + * there are any QTDs still attached to the QH, the QH is added to either the + * periodic inactive schedule or the periodic ready schedule and its next + * scheduled frame is calculated. The QH is placed in the ready schedule if + * the scheduled frame has been reached already. Otherwise it's placed in the + * inactive schedule. If there are no QTDs attached to the QH, the QH is + * completely removed from the periodic schedule. + */ +void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, + int sched_next_periodic_split) +{ + uint64_t flags; + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); + + if (dwc_qh_is_non_per(qh)) { + dwc_otg_hcd_qh_remove(hcd, qh); + if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) { + /* Add back to inactive non-periodic schedule. */ + dwc_otg_hcd_qh_add(hcd, qh); + } + } else { + uint16_t frame_number = dwc_otg_hcd_get_frame_number(hcd); + + if (qh->do_split) { + /* Schedule the next continuing periodic split transfer */ + if (sched_next_periodic_split) { + + qh->sched_frame = frame_number; + if (dwc_frame_num_le(frame_number, + dwc_frame_num_inc(qh-> + start_split_frame, + 1))) { + /* + * Allow one frame to elapse after start + * split microframe before scheduling + * complete split, but DONT if we are + * doing the next start split in the + * same frame for an ISOC out. + */ + if ((qh->ep_type != UE_ISOCHRONOUS) || + (qh->ep_is_in != 0)) { + qh->sched_frame = + dwc_frame_num_inc(qh->sched_frame, 1); + } + } + } else { + qh->sched_frame = + dwc_frame_num_inc(qh->start_split_frame, + qh->interval); + if (dwc_frame_num_le + (qh->sched_frame, frame_number)) { + qh->sched_frame = frame_number; + } + qh->sched_frame |= 0x7; + qh->start_split_frame = qh->sched_frame; + } + } else { + qh->sched_frame = + dwc_frame_num_inc(qh->sched_frame, qh->interval); + if (dwc_frame_num_le(qh->sched_frame, frame_number)) { + qh->sched_frame = frame_number; + } + } + + if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) { + dwc_otg_hcd_qh_remove(hcd, qh); + } else { + /* + * Remove from periodic_sched_queued and move to + * appropriate queue. + */ + if (qh->sched_frame == frame_number) { + DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready, + &qh->qh_list_entry); + } else { + DWC_LIST_MOVE_HEAD(&hcd-> + periodic_sched_inactive, + &qh->qh_list_entry); + } + } + } + + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); +} + +/** + * This function allocates and initializes a QTD. + * + * @param urb The URB to create a QTD from. Each URB-QTD pair will end up + * pointing to each other so each pair should have a unique correlation. + * + * @return Returns pointer to the newly allocated QTD, or NULL on error. */ +dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb) +{ + dwc_otg_qtd_t *qtd; + + qtd = dwc_otg_hcd_qtd_alloc(); + if (qtd == NULL) { + return NULL; + } + + dwc_otg_hcd_qtd_init(qtd, urb); + return qtd; +} + +/** + * Initializes a QTD structure. + * + * @param qtd The QTD to initialize. + * @param urb The URB to use for initialization. */ +void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb) +{ + dwc_memset(qtd, 0, sizeof(dwc_otg_qtd_t)); + qtd->urb = urb; + if (dwc_otg_hcd_get_pipe_type(&urb->pipe_info) == UE_CONTROL) { + /* + * The only time the QTD data toggle is used is on the data + * phase of control transfers. This phase always starts with + * DATA1. + */ + qtd->data_toggle = DWC_OTG_HC_PID_DATA1; + qtd->control_phase = DWC_OTG_CONTROL_SETUP; + } + + /* start split */ + qtd->complete_split = 0; + qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL; + qtd->isoc_split_offset = 0; + qtd->in_process = 0; + + /* Store the qtd ptr in the urb to reference what QTD. */ + urb->qtd = qtd; + return; +} + +/** + * This function adds a QTD to the QTD-list of a QH. It will find the correct + * QH to place the QTD into. If it does not find a QH, then it will create a + * new QH. If the QH to which the QTD is added is not currently scheduled, it + * is placed into the proper schedule based on its EP type. + * + * @param[in] qtd The QTD to add + * @param[in] hcd The DWC HCD structure + * @param[out] qh out parameter to return queue head + * + * @return 0 if successful, negative error code otherwise. + */ +int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, + dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh) +{ + int retval = 0; + uint64_t flags; + + dwc_otg_hcd_urb_t *urb = qtd->urb; + + DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); + + /* + * Get the QH which holds the QTD-list to insert to. Create QH if it + * doesn't exist. + */ + if (*qh == NULL) { + *qh = dwc_otg_hcd_qh_create(hcd, urb); + if (*qh == NULL) { + retval = -1; + goto done; + } + } + + retval = dwc_otg_hcd_qh_add(hcd, *qh); + if (retval == 0) { + DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd, + qtd_list_entry); + } + + done: + DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); + + return retval; +} + +#endif /* DWC_DEVICE_ONLY */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd.c b/drivers/usb/host/dwc_otg/dwc_otg_pcd.c new file mode 100644 index 000000000000..6043b99239f4 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd.c @@ -0,0 +1,2067 @@ +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.c $ + * $Revision: #79 $ + * $Date: 2009/04/10 $ + * $Change: 1230501 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ +#ifndef DWC_HOST_ONLY + +/** @file + * This file implements PCD Core. All code in this file is portable and don't + * use any OS specific functions. + * PCD Core provides Interface, defined in + * header file, which can be used to implement OS specific PCD interface. + * + * An important function of the PCD is managing interrupts generated + * by the DWC_otg controller. The implementation of the DWC_otg device + * mode interrupt service routines is in dwc_otg_pcd_intr.c. + * + * @todo Add Device Mode test modes (Test J mode, Test K mode, etc). + * @todo Does it work when the request size is greater than DEPTSIZ + * transfer size + * + */ + +#include "dwc_otg_pcd.h" + +#ifdef DWC_UTE_CFI +#include "dwc_otg_cfi.h" + +extern int init_cfi(cfiobject_t * cfiobj); +#endif + +static dwc_otg_pcd_ep_t *get_ep_from_handle(dwc_otg_pcd_t * pcd, void *handle) +{ + int i; + if (pcd->ep0.priv == handle) { + return &pcd->ep0; + } + for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) { + if (pcd->in_ep[i].priv == handle) + return &pcd->in_ep[i]; + if (pcd->out_ep[i].priv == handle) + return &pcd->out_ep[i]; + } + + return NULL; +} + +/** + * This function completes a request. It call's the request call back. + */ +void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req, + int32_t status) +{ + unsigned stopped = ep->stopped; + + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, ep); + DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry); + + /* don't modify queue heads during completion callback */ + ep->stopped = 1; + DWC_SPINUNLOCK(ep->pcd->lock); + ep->pcd->fops->complete(ep->pcd, ep->priv, req->priv, status, + req->actual); + DWC_SPINLOCK(ep->pcd->lock); + + if (ep->pcd->request_pending > 0) { + --ep->pcd->request_pending; + } + + ep->stopped = stopped; + dwc_free(req); +} + +/** + * This function terminates all the requsts in the EP request queue. + */ +void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep) +{ + dwc_otg_pcd_request_t *req; + + ep->stopped = 1; + + /* called with irqs blocked?? */ + while (!DWC_CIRCLEQ_EMPTY(&ep->queue)) { + req = DWC_CIRCLEQ_FIRST(&ep->queue); + dwc_otg_request_done(ep, req, -DWC_E_SHUTDOWN); + } +} + +void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd, + const struct dwc_otg_pcd_function_ops *fops) +{ + pcd->fops = fops; +} + +/** + * PCD Callback function for initializing the PCD when switching to + * device mode. + * + * @param p void pointer to the dwc_otg_pcd_t + */ +static int32_t dwc_otg_pcd_start_cb(void *p) +{ + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p; + + /* + * Initialized the Core for Device mode. + */ + if (dwc_otg_is_device_mode(GET_CORE_IF(pcd))) { + dwc_otg_core_dev_init(GET_CORE_IF(pcd)); + } + return 1; +} + +/** CFI-specific buffer allocation function for EP */ +#ifdef DWC_UTE_CFI +uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr, + size_t buflen, int flags) +{ + dwc_otg_pcd_ep_t *ep; + ep = get_ep_from_handle(pcd, pep); + return pcd->cfi->ops.ep_alloc_buf(pcd->cfi, pcd, ep, addr, buflen, + flags); +} +#else +uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr, + size_t buflen, int flags); +#endif + +/** + * PCD Callback function for notifying the PCD when resuming from + * suspend. + * + * @param p void pointer to the dwc_otg_pcd_t + */ +static int32_t dwc_otg_pcd_resume_cb(void *p) +{ + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p; + + if (pcd->fops->resume) { + pcd->fops->resume(pcd); + } + + /* Stop the SRP timeout timer. */ + if ((GET_CORE_IF(pcd)->core_params->phy_type != DWC_PHY_TYPE_PARAM_FS) + || (!GET_CORE_IF(pcd)->core_params->i2c_enable)) { + if (GET_CORE_IF(pcd)->srp_timer_started) { + GET_CORE_IF(pcd)->srp_timer_started = 0; + DWC_TIMER_CANCEL(pcd->srp_timer); + } + } + return 1; +} + +/** + * PCD Callback function for notifying the PCD device is suspended. + * + * @param p void pointer to the dwc_otg_pcd_t + */ +static int32_t dwc_otg_pcd_suspend_cb(void *p) +{ + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p; + + if (pcd->fops->suspend) { + pcd->fops->suspend(pcd); + } + + return 1; +} + +/** + * PCD Callback function for stopping the PCD when switching to Host + * mode. + * + * @param p void pointer to the dwc_otg_pcd_t + */ +static int32_t dwc_otg_pcd_stop_cb(void *p) +{ + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p; + extern void dwc_otg_pcd_stop(dwc_otg_pcd_t * _pcd); + + dwc_otg_pcd_stop(pcd); + return 1; +} + +/** + * PCD Callback structure for handling mode switching. + */ +static dwc_otg_cil_callbacks_t pcd_callbacks = { + .start = dwc_otg_pcd_start_cb, + .stop = dwc_otg_pcd_stop_cb, + .suspend = dwc_otg_pcd_suspend_cb, + .resume_wakeup = dwc_otg_pcd_resume_cb, + .p = 0, /* Set at registration */ +}; + +/** + * This function allocates a DMA Descriptor chain for the Endpoint + * buffer to be used for a transfer to/from the specified endpoint. + */ +dwc_otg_dev_dma_desc_t *dwc_otg_ep_alloc_desc_chain(uint32_t * dma_desc_addr, + uint32_t count) +{ + + return dwc_dma_alloc(count * sizeof(dwc_otg_dev_dma_desc_t), dma_desc_addr); +} + +/** + * This function frees a DMA Descriptor chain that was allocated by ep_alloc_desc. + */ +void dwc_otg_ep_free_desc_chain(dwc_otg_dev_dma_desc_t * desc_addr, + uint32_t dma_desc_addr, uint32_t count) +{ + dwc_dma_free(count * sizeof(dwc_otg_dev_dma_desc_t), desc_addr, + dma_desc_addr); +} + +#ifdef DWC_EN_ISOC + +/** + * This function initializes a descriptor chain for Isochronous transfer + * + * @param core_if Programming view of DWC_otg controller. + * @param dwc_ep The EP to start the transfer on. + * + */ +void dwc_otg_iso_ep_start_ddma_transfer(dwc_otg_core_if_t * core_if, + dwc_ep_t * dwc_ep) +{ + + dsts_data_t dsts = {.d32 = 0 }; + depctl_data_t depctl = {.d32 = 0 }; + volatile uint32_t *addr; + int i, j; + + if (dwc_ep->is_in) + dwc_ep->desc_cnt = dwc_ep->buf_proc_intrvl / dwc_ep->bInterval; + else + dwc_ep->desc_cnt = + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm / + dwc_ep->bInterval; + + /** Allocate descriptors for double buffering */ + dwc_ep->iso_desc_addr = + dwc_otg_ep_alloc_desc_chain(&dwc_ep->iso_dma_desc_addr, + dwc_ep->desc_cnt * 2); + if (dwc_ep->desc_addr) { + DWC_WARN("%s, can't allocate DMA descriptor chain\n", __func__); + return; + } + + dsts.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts); + + /** ISO OUT EP */ + if (dwc_ep->is_in == 0) { + dev_dma_desc_sts_t sts = {.d32 = 0 }; + dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr; + dma_addr_t dma_ad; + uint32_t data_per_desc; + dwc_otg_dev_out_ep_regs_t *out_regs = + core_if->dev_if->out_ep_regs[dwc_ep->num]; + int offset; + + addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl; + dma_ad = (dma_addr_t) dwc_read_reg32(&(out_regs->doepdma)); + + /** Buffer 0 descriptors setup */ + dma_ad = dwc_ep->dma_addr0; + + sts.b_iso_out.bs = BS_HOST_READY; + sts.b_iso_out.rxsts = 0; + sts.b_iso_out.l = 0; + sts.b_iso_out.sp = 0; + sts.b_iso_out.ioc = 0; + sts.b_iso_out.pid = 0; + sts.b_iso_out.framenum = 0; + + offset = 0; + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm; + i += dwc_ep->pkt_per_frm) { + + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) { + data_per_desc = + ((j + 1) * dwc_ep->maxpacket > + dwc_ep->data_per_frame) ? dwc_ep-> + data_per_frame - + j * dwc_ep->maxpacket : dwc_ep->maxpacket; + + data_per_desc += + (data_per_desc % 4) ? (4 - + data_per_desc % + 4) : 0; + sts.b_iso_out.rxbytes = data_per_desc; + dma_desc->buf = dma_ad; + dma_desc->status.d32 = sts.d32; + + offset += data_per_desc; + dma_desc++; + dma_ad += data_per_desc; + } + } + + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) { + data_per_desc = + ((j + 1) * dwc_ep->maxpacket > + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame - + j * dwc_ep->maxpacket : dwc_ep->maxpacket; + data_per_desc += + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0; + sts.b_iso_out.rxbytes = data_per_desc; + dma_desc->buf = dma_ad; + dma_desc->status.d32 = sts.d32; + + offset += data_per_desc; + dma_desc++; + dma_ad += data_per_desc; + } + + sts.b_iso_out.ioc = 1; + data_per_desc = + ((j + 1) * dwc_ep->maxpacket > + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame - + j * dwc_ep->maxpacket : dwc_ep->maxpacket; + data_per_desc += + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0; + sts.b_iso_out.rxbytes = data_per_desc; + + dma_desc->buf = dma_ad; + dma_desc->status.d32 = sts.d32; + dma_desc++; + + /** Buffer 1 descriptors setup */ + sts.b_iso_out.ioc = 0; + dma_ad = dwc_ep->dma_addr1; + + offset = 0; + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm; + i += dwc_ep->pkt_per_frm) { + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) { + data_per_desc = + ((j + 1) * dwc_ep->maxpacket > + dwc_ep->data_per_frame) ? dwc_ep-> + data_per_frame - + j * dwc_ep->maxpacket : dwc_ep->maxpacket; + data_per_desc += + (data_per_desc % 4) ? (4 - + data_per_desc % + 4) : 0; + sts.b_iso_out.rxbytes = data_per_desc; + dma_desc->buf = dma_ad; + dma_desc->status.d32 = sts.d32; + + offset += data_per_desc; + dma_desc++; + dma_ad += data_per_desc; + } + } + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) { + data_per_desc = + ((j + 1) * dwc_ep->maxpacket > + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame - + j * dwc_ep->maxpacket : dwc_ep->maxpacket; + data_per_desc += + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0; + sts.b_iso_out.rxbytes = data_per_desc; + dma_desc->buf = dma_ad; + dma_desc->status.d32 = sts.d32; + + offset += data_per_desc; + dma_desc++; + dma_ad += data_per_desc; + } + + sts.b_iso_out.ioc = 1; + sts.b_iso_out.l = 1; + data_per_desc = + ((j + 1) * dwc_ep->maxpacket > + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame - + j * dwc_ep->maxpacket : dwc_ep->maxpacket; + data_per_desc += + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0; + sts.b_iso_out.rxbytes = data_per_desc; + + dma_desc->buf = dma_ad; + dma_desc->status.d32 = sts.d32; + + dwc_ep->next_frame = 0; + + /** Write dma_ad into DOEPDMA register */ + dwc_write_reg32(&(out_regs->doepdma), + (uint32_t) dwc_ep->iso_dma_desc_addr); + + } + /** ISO IN EP */ + else { + dev_dma_desc_sts_t sts = {.d32 = 0 }; + dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr; + dma_addr_t dma_ad; + dwc_otg_dev_in_ep_regs_t *in_regs = + core_if->dev_if->in_ep_regs[dwc_ep->num]; + unsigned int frmnumber; + fifosize_data_t txfifosize, rxfifosize; + + txfifosize.d32 = + dwc_read_reg32(&core_if->dev_if->in_ep_regs[dwc_ep->num]-> + dtxfsts); + rxfifosize.d32 = + dwc_read_reg32(&core_if->core_global_regs->grxfsiz); + + addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl; + + dma_ad = dwc_ep->dma_addr0; + + dsts.d32 = + dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts); + + sts.b_iso_in.bs = BS_HOST_READY; + sts.b_iso_in.txsts = 0; + sts.b_iso_in.sp = + (dwc_ep->data_per_frame % dwc_ep->maxpacket) ? 1 : 0; + sts.b_iso_in.ioc = 0; + sts.b_iso_in.pid = dwc_ep->pkt_per_frm; + + frmnumber = dwc_ep->next_frame; + + sts.b_iso_in.framenum = frmnumber; + sts.b_iso_in.txbytes = dwc_ep->data_per_frame; + sts.b_iso_in.l = 0; + + /** Buffer 0 descriptors setup */ + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) { + dma_desc->buf = dma_ad; + dma_desc->status.d32 = sts.d32; + dma_desc++; + + dma_ad += dwc_ep->data_per_frame; + sts.b_iso_in.framenum += dwc_ep->bInterval; + } + + sts.b_iso_in.ioc = 1; + dma_desc->buf = dma_ad; + dma_desc->status.d32 = sts.d32; + ++dma_desc; + + /** Buffer 1 descriptors setup */ + sts.b_iso_in.ioc = 0; + dma_ad = dwc_ep->dma_addr1; + + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm; + i += dwc_ep->pkt_per_frm) { + dma_desc->buf = dma_ad; + dma_desc->status.d32 = sts.d32; + dma_desc++; + + dma_ad += dwc_ep->data_per_frame; + sts.b_iso_in.framenum += dwc_ep->bInterval; + + sts.b_iso_in.ioc = 0; + } + sts.b_iso_in.ioc = 1; + sts.b_iso_in.l = 1; + + dma_desc->buf = dma_ad; + dma_desc->status.d32 = sts.d32; + + dwc_ep->next_frame = sts.b_iso_in.framenum + dwc_ep->bInterval; + + /** Write dma_ad into diepdma register */ + dwc_write_reg32(&(in_regs->diepdma), + (uint32_t) dwc_ep->iso_dma_desc_addr); + } + /** Enable endpoint, clear nak */ + depctl.d32 = 0; + depctl.b.epena = 1; + depctl.b.usbactep = 1; + depctl.b.cnak = 1; + + dwc_modify_reg32(addr, depctl.d32, depctl.d32); + depctl.d32 = dwc_read_reg32(addr); +} + +/** + * This function initializes a descriptor chain for Isochronous transfer + * + * @param core_if Programming view of DWC_otg controller. + * @param ep The EP to start the transfer on. + * + */ + +void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if, + dwc_ep_t * ep) +{ + depctl_data_t depctl = {.d32 = 0 }; + volatile uint32_t *addr; + + if (ep->is_in) { + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl; + } else { + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl; + } + + if (core_if->dma_enable == 0 || core_if->dma_desc_enable != 0) { + return; + } else { + deptsiz_data_t deptsiz = {.d32 = 0 }; + + ep->xfer_len = + ep->data_per_frame * ep->buf_proc_intrvl / ep->bInterval; + ep->pkt_cnt = + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket; + ep->xfer_count = 0; + ep->xfer_buff = + (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0; + ep->dma_addr = + (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0; + + if (ep->is_in) { + /* Program the transfer size and packet count + * as follows: xfersize = N * maxpacket + + * short_packet pktcnt = N + (short_packet + * exist ? 1 : 0) + */ + deptsiz.b.mc = ep->pkt_per_frm; + deptsiz.b.xfersize = ep->xfer_len; + deptsiz.b.pktcnt = + (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket; + dwc_write_reg32(&core_if->dev_if->in_ep_regs[ep->num]-> + dieptsiz, deptsiz.d32); + + /* Write the DMA register */ + dwc_write_reg32(& + (core_if->dev_if->in_ep_regs[ep->num]-> + diepdma), (uint32_t) ep->dma_addr); + + } else { + deptsiz.b.pktcnt = + (ep->xfer_len + (ep->maxpacket - 1)) / + ep->maxpacket; + deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket; + + dwc_write_reg32(&core_if->dev_if->out_ep_regs[ep->num]-> + doeptsiz, deptsiz.d32); + + /* Write the DMA register */ + dwc_write_reg32(& + (core_if->dev_if->out_ep_regs[ep->num]-> + doepdma), (uint32_t) ep->dma_addr); + + } + /** Enable endpoint, clear nak */ + depctl.d32 = 0; + dwc_modify_reg32(addr, depctl.d32, depctl.d32); + + depctl.b.epena = 1; + depctl.b.cnak = 1; + + dwc_modify_reg32(addr, depctl.d32, depctl.d32); + } +} + +/** + * This function does the setup for a data transfer for an EP and + * starts the transfer. For an IN transfer, the packets will be + * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers, + * the packets are unloaded from the Rx FIFO in the ISR. the ISR. + * + * @param core_if Programming view of DWC_otg controller. + * @param ep The EP to start the transfer on. + */ + +static void dwc_otg_iso_ep_start_transfer(dwc_otg_core_if_t * core_if, + dwc_ep_t * ep) +{ + if (core_if->dma_enable) { + if (core_if->dma_desc_enable) { + if (ep->is_in) { + ep->desc_cnt = ep->pkt_cnt / ep->pkt_per_frm; + } else { + ep->desc_cnt = ep->pkt_cnt; + } + dwc_otg_iso_ep_start_ddma_transfer(core_if, ep); + } else { + if (core_if->pti_enh_enable) { + dwc_otg_iso_ep_start_buf_transfer(core_if, ep); + } else { + ep->cur_pkt_addr = + (ep->proc_buf_num) ? ep->xfer_buff1 : ep-> + xfer_buff0; + ep->cur_pkt_dma_addr = + (ep->proc_buf_num) ? ep->dma_addr1 : ep-> + dma_addr0; + dwc_otg_iso_ep_start_frm_transfer(core_if, ep); + } + } + } else { + ep->cur_pkt_addr = + (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0; + ep->cur_pkt_dma_addr = + (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0; + dwc_otg_iso_ep_start_frm_transfer(core_if, ep); + } +} + +/** + * This function does the setup for a data transfer for an EP and + * starts the transfer. For an IN transfer, the packets will be + * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers, + * the packets are unloaded from the Rx FIFO in the ISR. the ISR. + * + * @param core_if Programming view of DWC_otg controller. + * @param ep The EP to start the transfer on. + */ + +void dwc_otg_iso_ep_stop_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep) +{ + depctl_data_t depctl = {.d32 = 0 }; + volatile uint32_t *addr; + + if (ep->is_in == 1) { + addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl; + } else { + addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl; + } + + /* disable the ep */ + depctl.d32 = dwc_read_reg32(addr); + + depctl.b.epdis = 1; + depctl.b.snak = 1; + + dwc_write_reg32(addr, depctl.d32); + + if (core_if->dma_desc_enable && + ep->iso_desc_addr && ep->iso_dma_desc_addr) { + dwc_otg_ep_free_desc_chain(ep->iso_desc_addr, + ep->iso_dma_desc_addr, + ep->desc_cnt * 2); + } + + /* reset varibales */ + ep->dma_addr0 = 0; + ep->dma_addr1 = 0; + ep->xfer_buff0 = 0; + ep->xfer_buff1 = 0; + ep->data_per_frame = 0; + ep->data_pattern_frame = 0; + ep->sync_frame = 0; + ep->buf_proc_intrvl = 0; + ep->bInterval = 0; + ep->proc_buf_num = 0; + ep->pkt_per_frm = 0; + ep->pkt_per_frm = 0; + ep->desc_cnt = 0; + ep->iso_desc_addr = 0; + ep->iso_dma_desc_addr = 0; +} + +int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle, + uint8_t * buf0, uint8_t * buf1, dwc_dma_t dma0, + dwc_dma_t dma1, int sync_frame, int dp_frame, + int data_per_frame, int start_frame, + int buf_proc_intrvl, void *req_handle, + int atomic_alloc) +{ + dwc_otg_pcd_ep_t *ep; + uint64_t flags = 0; + dwc_ep_t *dwc_ep; + int32_t frm_data; + dsts_data_t dsts; + dwc_otg_core_if_t *core_if; + + ep = get_ep_from_handle(pcd, ep_handle); + + if (!ep->desc || ep->dwc_ep.num == 0) { + DWC_WARN("bad ep\n"); + return -DWC_E_INVALID; + } + + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); + core_if = GET_CORE_IF(pcd); + dwc_ep = &ep->dwc_ep; + + if (ep->iso_req_handle) { + DWC_WARN("ISO request in progress\n"); + } + + dwc_ep->dma_addr0 = dma0; + dwc_ep->dma_addr1 = dma1; + + dwc_ep->xfer_buff0 = buf0; + dwc_ep->xfer_buff1 = buf1; + + dwc_ep->data_per_frame = data_per_frame; + + /** @todo - pattern data support is to be implemented in the future */ + dwc_ep->data_pattern_frame = dp_frame; + dwc_ep->sync_frame = sync_frame; + + dwc_ep->buf_proc_intrvl = buf_proc_intrvl; + + dwc_ep->bInterval = 1 << (ep->desc->bInterval - 1); + + dwc_ep->proc_buf_num = 0; + + dwc_ep->pkt_per_frm = 0; + frm_data = ep->dwc_ep.data_per_frame; + while (frm_data > 0) { + dwc_ep->pkt_per_frm++; + frm_data -= ep->dwc_ep.maxpacket; + } + + dsts.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts); + + if (start_frame == -1) { + dwc_ep->next_frame = dsts.b.soffn + 1; + if (dwc_ep->bInterval != 1) { + dwc_ep->next_frame = + dwc_ep->next_frame + (dwc_ep->bInterval - 1 - + dwc_ep->next_frame % + dwc_ep->bInterval); + } + } else { + dwc_ep->next_frame = start_frame; + } + + if (!core_if->pti_enh_enable) { + dwc_ep->pkt_cnt = + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm / + dwc_ep->bInterval; + } else { + dwc_ep->pkt_cnt = + (dwc_ep->data_per_frame * + (dwc_ep->buf_proc_intrvl / dwc_ep->bInterval) + - 1 + dwc_ep->maxpacket) / dwc_ep->maxpacket; + } + + if (core_if->dma_desc_enable) { + dwc_ep->desc_cnt = + dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm / + dwc_ep->bInterval; + } + + if (atomic_alloc) { + dwc_ep->pkt_info = + dwc_alloc_atomic(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt); + } else { + dwc_ep->pkt_info = + dwc_alloc(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt); + } + if (!dwc_ep->pkt_info) { + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); + return -DWC_E_NO_MEMORY; + } + if (core_if->pti_enh_enable) { + dwc_memset(dwc_ep->pkt_info, 0, + sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt); + } + + dwc_ep->cur_pkt = 0; + ep->iso_req_handle = req_handle; + + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); + dwc_otg_iso_ep_start_transfer(core_if, dwc_ep); + return 0; +} + +int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle, + void *req_handle) +{ + uint64_t flags = 0; + dwc_otg_pcd_ep_t *ep; + dwc_ep_t *dwc_ep; + + ep = get_ep_from_handle(pcd, ep_handle); + if (!ep || !ep->desc || ep->dwc_ep.num == 0) { + DWC_WARN("bad ep\n"); + return -DWC_E_INVALID; + } + dwc_ep = &ep->dwc_ep; + + dwc_otg_iso_ep_stop_transfer(GET_CORE_IF(pcd), dwc_ep); + + dwc_free(dwc_ep->pkt_info); + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); + if (ep->iso_req_handle != req_handle) { + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); + return -DWC_E_INVALID; + } + + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); + + ep->iso_req_handle = 0; + return 0; +} + +/** + * This function is used for perodical data exchnage between PCD and gadget drivers. + * for Isochronous EPs + * + * - Every time a sync period completes this function is called to + * perform data exchange between PCD and gadget + */ +void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep, + void *req_handle) +{ + int i; + dwc_ep_t *dwc_ep; + + dwc_ep = &ep->dwc_ep; + + DWC_SPINUNLOCK(ep->pcd->lock); + pcd->fops->isoc_complete(pcd, ep->priv, ep->iso_req_handle, + dwc_ep->proc_buf_num ^ 0x1); + DWC_SPINLOCK(ep->pcd->lock); + + for (i = 0; i < dwc_ep->pkt_cnt; ++i) { + dwc_ep->pkt_info[i].status = 0; + dwc_ep->pkt_info[i].offset = 0; + dwc_ep->pkt_info[i].length = 0; + } +} + +int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd, void *ep_handle, + void *iso_req_handle) +{ + dwc_otg_pcd_ep_t *ep; + dwc_ep_t *dwc_ep; + + ep = get_ep_from_handle(pcd, ep_handle); + dwc_ep = &ep->dwc_ep; + + return dwc_ep->pkt_cnt; +} + +void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd, void *ep_handle, + void *iso_req_handle, int packet, + int *status, int *actual, int *offset) +{ + dwc_otg_pcd_ep_t *ep; + dwc_ep_t *dwc_ep; + + ep = get_ep_from_handle(pcd, ep_handle); + dwc_ep = &ep->dwc_ep; + + *status = dwc_ep->pkt_info[packet].status; + *actual = dwc_ep->pkt_info[packet].length; + *offset = dwc_ep->pkt_info[packet].offset; +} + +#endif /* DWC_EN_ISOC */ + +static void dwc_otg_pcd_init_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * pcd_ep, + uint32_t is_in, uint32_t ep_num) +{ + /* Init EP structure */ + pcd_ep->desc = 0; + pcd_ep->pcd = pcd; + pcd_ep->stopped = 1; + pcd_ep->queue_sof = 0; + + /* Init DWC ep structure */ + pcd_ep->dwc_ep.is_in = is_in; + pcd_ep->dwc_ep.num = ep_num; + pcd_ep->dwc_ep.active = 0; + pcd_ep->dwc_ep.tx_fifo_num = 0; + /* Control until ep is actvated */ + pcd_ep->dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL; + pcd_ep->dwc_ep.maxpacket = MAX_PACKET_SIZE; + pcd_ep->dwc_ep.dma_addr = 0; + pcd_ep->dwc_ep.start_xfer_buff = 0; + pcd_ep->dwc_ep.xfer_buff = 0; + pcd_ep->dwc_ep.xfer_len = 0; + pcd_ep->dwc_ep.xfer_count = 0; + pcd_ep->dwc_ep.sent_zlp = 0; + pcd_ep->dwc_ep.total_len = 0; + pcd_ep->dwc_ep.desc_addr = 0; + pcd_ep->dwc_ep.dma_desc_addr = 0; + DWC_CIRCLEQ_INIT(&pcd_ep->queue); +} + +/** + * Initialise ep's + */ +static void dwc_otg_pcd_reinit(dwc_otg_pcd_t * pcd) +{ + int i; + uint32_t hwcfg1; + dwc_otg_pcd_ep_t *ep; + int in_ep_cntr, out_ep_cntr; + uint32_t num_in_eps = (GET_CORE_IF(pcd))->dev_if->num_in_eps; + uint32_t num_out_eps = (GET_CORE_IF(pcd))->dev_if->num_out_eps; + + /** + * Initialize the EP0 structure. + */ + ep = &pcd->ep0; + dwc_otg_pcd_init_ep(pcd, ep, 0, 0); + + in_ep_cntr = 0; + hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 3; + for (i = 1; in_ep_cntr < num_in_eps; i++) { + if ((hwcfg1 & 0x1) == 0) { + dwc_otg_pcd_ep_t *ep = &pcd->in_ep[in_ep_cntr]; + in_ep_cntr++; + /** + * @todo NGS: Add direction to EP, based on contents + * of HWCFG1. Need a copy of HWCFG1 in pcd structure? + * sprintf(";r + */ + dwc_otg_pcd_init_ep(pcd, ep, 1 /* IN */ , i); + + DWC_CIRCLEQ_INIT(&ep->queue); + } + hwcfg1 >>= 2; + } + + out_ep_cntr = 0; + hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 2; + for (i = 1; out_ep_cntr < num_out_eps; i++) { + if ((hwcfg1 & 0x1) == 0) { + dwc_otg_pcd_ep_t *ep = &pcd->out_ep[out_ep_cntr]; + out_ep_cntr++; + /** + * @todo NGS: Add direction to EP, based on contents + * of HWCFG1. Need a copy of HWCFG1 in pcd structure? + * sprintf(";r + */ + dwc_otg_pcd_init_ep(pcd, ep, 0 /* OUT */ , i); + DWC_CIRCLEQ_INIT(&ep->queue); + } + hwcfg1 >>= 2; + } + + pcd->ep0state = EP0_DISCONNECT; + pcd->ep0.dwc_ep.maxpacket = MAX_EP0_SIZE; + pcd->ep0.dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL; +} + +/** + * This function is called when the SRP timer expires. The SRP should + * complete within 6 seconds. + */ +static void srp_timeout(void *ptr) +{ + gotgctl_data_t gotgctl; + dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr; + volatile uint32_t *addr = &core_if->core_global_regs->gotgctl; + + gotgctl.d32 = dwc_read_reg32(addr); + + core_if->srp_timer_started = 0; + + if ((core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS) && + (core_if->core_params->i2c_enable)) { + DWC_PRINTF("SRP Timeout\n"); + + if ((core_if->srp_success) && (gotgctl.b.bsesvld)) { + if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) { + core_if->pcd_cb->resume_wakeup(core_if->pcd_cb-> + p); + } + + /* Clear Session Request */ + gotgctl.d32 = 0; + gotgctl.b.sesreq = 1; + dwc_modify_reg32(&core_if->core_global_regs->gotgctl, + gotgctl.d32, 0); + + core_if->srp_success = 0; + } else { + __DWC_ERROR("Device not connected/responding\n"); + gotgctl.b.sesreq = 0; + dwc_write_reg32(addr, gotgctl.d32); + } + } else if (gotgctl.b.sesreq) { + DWC_PRINTF("SRP Timeout\n"); + + __DWC_ERROR("Device not connected/responding\n"); + gotgctl.b.sesreq = 0; + dwc_write_reg32(addr, gotgctl.d32); + } else { + DWC_PRINTF(" SRP GOTGCTL=%0x\n", gotgctl.d32); + } +} + +/** + * Tasklet + * + */ +extern void start_next_request(dwc_otg_pcd_ep_t * ep); + +static void start_xfer_tasklet_func(void *data) +{ + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data; + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); + + int i; + depctl_data_t diepctl; + + DWC_DEBUGPL(DBG_PCDV, "Start xfer tasklet\n"); + + diepctl.d32 = dwc_read_reg32(&core_if->dev_if->in_ep_regs[0]->diepctl); + + if (pcd->ep0.queue_sof) { + pcd->ep0.queue_sof = 0; + start_next_request(&pcd->ep0); + // break; + } + + for (i = 0; i < core_if->dev_if->num_in_eps; i++) { + depctl_data_t diepctl; + diepctl.d32 = + dwc_read_reg32(&core_if->dev_if->in_ep_regs[i]->diepctl); + + if (pcd->in_ep[i].queue_sof) { + pcd->in_ep[i].queue_sof = 0; + start_next_request(&pcd->in_ep[i]); + // break; + } + } + + return; +} + +/** + * This function initialized the PCD portion of the driver. + * + */ +dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if) +{ + dwc_otg_pcd_t *pcd = 0; + dwc_otg_dev_if_t *dev_if; + + /* + * Allocate PCD structure + */ + pcd = dwc_alloc(sizeof(dwc_otg_pcd_t)); + + if (pcd == 0) { + return NULL; + } + + pcd->lock = DWC_SPINLOCK_ALLOC(); + DWC_DEBUGPL(DBG_HCDV, "Init of PCD %p given core_if %p\n", + pcd, core_if);//GRAYG + pcd->core_if = core_if; + if (!pcd->lock) { + DWC_ERROR("Could not allocate lock for pcd"); + dwc_free(pcd); + return NULL; + } + dev_if = core_if->dev_if; + + if (core_if->hwcfg4.b.ded_fifo_en) { + DWC_PRINTF("Dedicated Tx FIFOs mode\n"); + } else { + DWC_PRINTF("Shared Tx FIFO mode\n"); + } + + /* + * Initialized the Core for Device mode. + */ + if (dwc_otg_is_device_mode(core_if)) { + dwc_otg_core_dev_init(core_if); + } + + /* + * Register the PCD Callbacks. + */ + dwc_otg_cil_register_pcd_callbacks(core_if, &pcd_callbacks, pcd); + + /* + * Initialize the DMA buffer for SETUP packets + */ + if (GET_CORE_IF(pcd)->dma_enable) { + pcd->setup_pkt = + dwc_dma_alloc(sizeof(*pcd->setup_pkt) * 5, + &pcd->setup_pkt_dma_handle); + if (pcd->setup_pkt == 0) { + dwc_free(pcd); + return NULL; + } + + pcd->status_buf = + dwc_dma_alloc(sizeof(uint16_t), + &pcd->status_buf_dma_handle); + if (pcd->status_buf == 0) { + dwc_dma_free(sizeof(*pcd->setup_pkt) * 5, + pcd->setup_pkt, pcd->setup_pkt_dma_handle); + dwc_free(pcd); + return NULL; + } + + if (GET_CORE_IF(pcd)->dma_desc_enable) { + dev_if->setup_desc_addr[0] = + dwc_otg_ep_alloc_desc_chain(&dev_if-> + dma_setup_desc_addr[0], + 1); + dev_if->setup_desc_addr[1] = + dwc_otg_ep_alloc_desc_chain(&dev_if-> + dma_setup_desc_addr[1], + 1); + dev_if->in_desc_addr = + dwc_otg_ep_alloc_desc_chain(&dev_if-> + dma_in_desc_addr, 1); + dev_if->out_desc_addr = + dwc_otg_ep_alloc_desc_chain(&dev_if-> + dma_out_desc_addr, 1); + + if (dev_if->setup_desc_addr[0] == 0 + || dev_if->setup_desc_addr[1] == 0 + || dev_if->in_desc_addr == 0 + || dev_if->out_desc_addr == 0) { + + if (dev_if->out_desc_addr) + dwc_otg_ep_free_desc_chain(dev_if-> + out_desc_addr, + dev_if-> + dma_out_desc_addr, + 1); + if (dev_if->in_desc_addr) + dwc_otg_ep_free_desc_chain(dev_if-> + in_desc_addr, + dev_if-> + dma_in_desc_addr, + 1); + if (dev_if->setup_desc_addr[1]) + dwc_otg_ep_free_desc_chain(dev_if-> + setup_desc_addr + [1], + dev_if-> + dma_setup_desc_addr + [1], 1); + if (dev_if->setup_desc_addr[0]) + dwc_otg_ep_free_desc_chain(dev_if-> + setup_desc_addr + [0], + dev_if-> + dma_setup_desc_addr + [0], 1); + + dwc_dma_free(sizeof(*pcd->setup_pkt) * 5, + pcd->setup_pkt, + pcd->setup_pkt_dma_handle); + dwc_dma_free(sizeof(*pcd->status_buf), + pcd->status_buf, + pcd->status_buf_dma_handle); + + dwc_free(pcd); + + return NULL; + } + } + } else { + pcd->setup_pkt = dwc_alloc(sizeof(*pcd->setup_pkt) * 5); + if (pcd->setup_pkt == 0) { + dwc_free(pcd); + return NULL; + } + + pcd->status_buf = dwc_alloc(sizeof(uint16_t)); + if (pcd->status_buf == 0) { + dwc_free(pcd->setup_pkt); + dwc_free(pcd); + return NULL; + } + } + + dwc_otg_pcd_reinit(pcd); + + /* Allocate the cfi object for the PCD */ +#ifdef DWC_UTE_CFI + pcd->cfi = dwc_alloc(sizeof(cfiobject_t)); + if (NULL == pcd->cfi) + return NULL; + if (init_cfi(pcd->cfi)) { + CFI_INFO("%s: Failed to init the CFI object\n", __func__); + return NULL; + } +#endif + + /* Initialize tasklets */ + pcd->start_xfer_tasklet = DWC_TASK_ALLOC(start_xfer_tasklet_func, pcd); + pcd->test_mode_tasklet = DWC_TASK_ALLOC(do_test_mode, pcd); + /* Initialize timer */ + pcd->srp_timer = DWC_TIMER_ALLOC("SRP TIMER", srp_timeout, core_if); + return pcd; +} + +void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd) +{ + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if; + + if (GET_CORE_IF(pcd)->dma_enable) { + dwc_dma_free(sizeof(*pcd->setup_pkt) * 5, pcd->setup_pkt, + pcd->setup_pkt_dma_handle); + dwc_dma_free(sizeof(uint16_t), pcd->status_buf, + pcd->status_buf_dma_handle); + if (GET_CORE_IF(pcd)->dma_desc_enable) { + dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[0], + dev_if-> + dma_setup_desc_addr[0], 1); + dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[1], + dev_if-> + dma_setup_desc_addr[1], 1); + dwc_otg_ep_free_desc_chain(dev_if->in_desc_addr, + dev_if->dma_in_desc_addr, 1); + dwc_otg_ep_free_desc_chain(dev_if->out_desc_addr, + dev_if->dma_out_desc_addr, + 1); + } + } else { + dwc_free(pcd->setup_pkt); + dwc_free(pcd->status_buf); + } + DWC_SPINLOCK_FREE(pcd->lock); + DWC_TASK_FREE(pcd->start_xfer_tasklet); + DWC_TASK_FREE(pcd->test_mode_tasklet); + DWC_TIMER_FREE(pcd->srp_timer); + +/* Release the CFI object's dynamic memory */ +#ifdef DWC_UTE_CFI + if (pcd->cfi->ops.release) { + pcd->cfi->ops.release(pcd->cfi); + } +#endif + + dwc_free(pcd); +} + +uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd) +{ + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); + + if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) || + ((core_if->hwcfg2.b.hs_phy_type == 2) && + (core_if->hwcfg2.b.fs_phy_type == 1) && + (core_if->core_params->ulpi_fs_ls))) { + return 0; + } + + return 1; +} + +uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd) +{ + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); + gusbcfg_data_t usbcfg = {.d32 = 0 }; + + usbcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->gusbcfg); + if (!usbcfg.b.srpcap || !usbcfg.b.hnpcap) { + return 0; + } + + return 1; +} + +/** + * This function assigns periodic Tx FIFO to an periodic EP + * in shared Tx FIFO mode + */ +static uint32_t assign_tx_fifo(dwc_otg_core_if_t * core_if) +{ + uint32_t TxMsk = 1; + int i; + + for (i = 0; i < core_if->hwcfg4.b.num_in_eps; ++i) { + if ((TxMsk & core_if->tx_msk) == 0) { + core_if->tx_msk |= TxMsk; + return i + 1; + } + TxMsk <<= 1; + } + return 0; +} + +/** + * This function assigns periodic Tx FIFO to an periodic EP + * in shared Tx FIFO mode + */ +static uint32_t assign_perio_tx_fifo(dwc_otg_core_if_t * core_if) +{ + uint32_t PerTxMsk = 1; + int i; + for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; ++i) { + if ((PerTxMsk & core_if->p_tx_msk) == 0) { + core_if->p_tx_msk |= PerTxMsk; + return i + 1; + } + PerTxMsk <<= 1; + } + return 0; +} + +/** + * This function releases periodic Tx FIFO + * in shared Tx FIFO mode + */ +static void release_perio_tx_fifo(dwc_otg_core_if_t * core_if, + uint32_t fifo_num) +{ + core_if->p_tx_msk = + (core_if->p_tx_msk & (1 << (fifo_num - 1))) ^ core_if->p_tx_msk; +} + +/** + * This function releases periodic Tx FIFO + * in shared Tx FIFO mode + */ +static void release_tx_fifo(dwc_otg_core_if_t * core_if, uint32_t fifo_num) +{ + core_if->tx_msk = + (core_if->tx_msk & (1 << (fifo_num - 1))) ^ core_if->tx_msk; +} + +int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd, + const uint8_t * ep_desc, void *usb_ep) +{ + int num, dir; + dwc_otg_pcd_ep_t *ep = 0; + const usb_endpoint_descriptor_t *desc; + uint64_t flags; + int retval = 0; + + desc = (const usb_endpoint_descriptor_t *)ep_desc; + + if (!desc) { + pcd->ep0.priv = usb_ep; + ep = &pcd->ep0; + retval = -DWC_E_INVALID; + goto out; + } + + num = UE_GET_ADDR(desc->bEndpointAddress); + dir = UE_GET_DIR(desc->bEndpointAddress); + + if (!desc->wMaxPacketSize) { + DWC_WARN("bad maxpacketsize\n"); + retval = -DWC_E_INVALID; + goto out; + } + + if (dir == UE_DIR_IN) { + ep = &pcd->in_ep[num - 1]; + } else { + ep = &pcd->out_ep[num - 1]; + } + + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); + + ep->desc = desc; + ep->priv = usb_ep; + + /* + * Activate the EP + */ + ep->stopped = 0; + + ep->dwc_ep.is_in = (dir == UE_DIR_IN); + ep->dwc_ep.maxpacket = UGETW(desc->wMaxPacketSize); + + ep->dwc_ep.type = desc->bmAttributes & UE_XFERTYPE; + + if (ep->dwc_ep.is_in) { + if (!GET_CORE_IF(pcd)->en_multiple_tx_fifo) { + ep->dwc_ep.tx_fifo_num = 0; + + if (ep->dwc_ep.type == UE_ISOCHRONOUS) { + /* + * if ISOC EP then assign a Periodic Tx FIFO. + */ + ep->dwc_ep.tx_fifo_num = + assign_perio_tx_fifo(GET_CORE_IF(pcd)); + } + } else { + /* + * if Dedicated FIFOs mode is on then assign a Tx FIFO. + */ + ep->dwc_ep.tx_fifo_num = + assign_tx_fifo(GET_CORE_IF(pcd)); + + } + } + /* Set initial data PID. */ + if (ep->dwc_ep.type == UE_BULK) { + ep->dwc_ep.data_pid_start = 0; + } + + /* Alloc DMA Descriptors */ + if (GET_CORE_IF(pcd)->dma_desc_enable) { + if (ep->dwc_ep.type != UE_ISOCHRONOUS) { + ep->dwc_ep.desc_addr = + dwc_otg_ep_alloc_desc_chain(&ep->dwc_ep. + dma_desc_addr, + MAX_DMA_DESC_CNT); + if (!ep->dwc_ep.desc_addr) { + DWC_WARN("%s, can't allocate DMA descriptor\n", + __func__); + retval = -DWC_E_SHUTDOWN; + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); + goto out; + } + } + } + + DWC_DEBUGPL(DBG_PCD, "Activate %s: type=%d, mps=%d desc=%p\n", + (ep->dwc_ep.is_in ? "IN" : "OUT"), + ep->dwc_ep.type, ep->dwc_ep.maxpacket, ep->desc); + + dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep); + +#ifdef DWC_UTE_CFI + if (pcd->cfi->ops.ep_enable) { + pcd->cfi->ops.ep_enable(pcd->cfi, pcd, ep); + } +#endif + + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); + + out: + return retval; +} + +int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle) +{ + dwc_otg_pcd_ep_t *ep; + uint64_t flags; + dwc_otg_dev_dma_desc_t *desc_addr; + dwc_dma_t dma_desc_addr; + + ep = get_ep_from_handle(pcd, ep_handle); + + if (!ep || !ep->desc) { + DWC_DEBUGPL(DBG_PCD, "%s, %d %s not enabled\n", __func__, + ep->dwc_ep.num, ep->dwc_ep.is_in ? "IN" : "OUT"); + return -DWC_E_INVALID; + } + + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); + + dwc_otg_request_nuke(ep); + + dwc_otg_ep_deactivate(GET_CORE_IF(pcd), &ep->dwc_ep); + ep->desc = 0; + ep->stopped = 1; + + if (ep->dwc_ep.is_in) { + dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num); + release_perio_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num); + release_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num); + } + + /* Free DMA Descriptors */ + if (GET_CORE_IF(pcd)->dma_desc_enable) { + if (ep->dwc_ep.type != UE_ISOCHRONOUS) { + desc_addr = ep->dwc_ep.desc_addr; + dma_desc_addr = ep->dwc_ep.dma_desc_addr; + + /* Cannot call dma_free_coherent() with IRQs disabled */ + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); + dwc_otg_ep_free_desc_chain(desc_addr, dma_desc_addr, + MAX_DMA_DESC_CNT); + + goto out_unlocked; + } + } + + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); + + out_unlocked: + DWC_DEBUGPL(DBG_PCD, "%d %s disabled\n", ep->dwc_ep.num, + ep->dwc_ep.is_in ? "IN" : "OUT"); + return 0; + +} + +int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle, + uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen, + int zero, void *req_handle, int atomic_alloc) +{ + int prevented = 0; + uint64_t flags; + dwc_otg_pcd_request_t *req; + dwc_otg_pcd_ep_t *ep; + uint32_t max_transfer; + + ep = get_ep_from_handle(pcd, ep_handle); + if ((!ep->desc && ep->dwc_ep.num != 0)) { + DWC_WARN("bad ep\n"); + return -DWC_E_INVALID; + } + + if (atomic_alloc) { + req = dwc_alloc_atomic(sizeof(*req)); + } else { + req = dwc_alloc(sizeof(*req)); + } + + if (!req) { + return -DWC_E_NO_MEMORY; + } + DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry); + if (!GET_CORE_IF(pcd)->core_params->opt) { + if (ep->dwc_ep.num != 0) { + DWC_ERROR("queue req %p, len %d buf %p\n", + req_handle, buflen, buf); + } + } + + req->buf = buf; + req->dma = dma_buf; + req->length = buflen; + req->sent_zlp = zero; + req->priv = req_handle; + + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); + + /* + * For EP0 IN without premature status, zlp is required? + */ + if (ep->dwc_ep.num == 0 && ep->dwc_ep.is_in) { + DWC_DEBUGPL(DBG_PCDV, "%d-OUT ZLP\n", ep->dwc_ep.num); + //_req->zero = 1; + } + + /* Start the transfer */ + if (DWC_CIRCLEQ_EMPTY(&ep->queue) && !ep->stopped) { + /* EP0 Transfer? */ + if (ep->dwc_ep.num == 0) { + switch (pcd->ep0state) { + case EP0_IN_DATA_PHASE: + DWC_DEBUGPL(DBG_PCD, + "%s ep0: EP0_IN_DATA_PHASE\n", + __func__); + break; + + case EP0_OUT_DATA_PHASE: + DWC_DEBUGPL(DBG_PCD, + "%s ep0: EP0_OUT_DATA_PHASE\n", + __func__); + if (pcd->request_config) { + /* Complete STATUS PHASE */ + ep->dwc_ep.is_in = 1; + pcd->ep0state = EP0_IN_STATUS_PHASE; + } + break; + + case EP0_IN_STATUS_PHASE: + DWC_DEBUGPL(DBG_PCD, + "%s ep0: EP0_IN_STATUS_PHASE\n", + __func__); + break; + + default: + DWC_DEBUGPL(DBG_ANY, "ep0: odd state %d\n", + pcd->ep0state); + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); + return -DWC_E_SHUTDOWN; + } + + ep->dwc_ep.dma_addr = dma_buf; + ep->dwc_ep.start_xfer_buff = buf; + ep->dwc_ep.xfer_buff = buf; + ep->dwc_ep.xfer_len = buflen; + ep->dwc_ep.xfer_count = 0; + ep->dwc_ep.sent_zlp = 0; + ep->dwc_ep.total_len = ep->dwc_ep.xfer_len; + + if (zero) { + if ((ep->dwc_ep.xfer_len % + ep->dwc_ep.maxpacket == 0) + && (ep->dwc_ep.xfer_len != 0)) { + ep->dwc_ep.sent_zlp = 1; + } + + } + + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), + &ep->dwc_ep); + } // non-ep0 endpoints + else { +#ifdef DWC_UTE_CFI + if (ep->dwc_ep.buff_mode != BM_STANDARD) { + /* store the request length */ + ep->dwc_ep.cfi_req_len = buflen; + pcd->cfi->ops.build_descriptors(pcd->cfi, pcd, + ep, req); + } else { +#endif + max_transfer = + GET_CORE_IF(ep->pcd)->core_params-> + max_transfer_size; + + /* Setup and start the Transfer */ + ep->dwc_ep.dma_addr = dma_buf; + ep->dwc_ep.start_xfer_buff = buf; + ep->dwc_ep.xfer_buff = buf; + ep->dwc_ep.xfer_len = 0; + ep->dwc_ep.xfer_count = 0; + ep->dwc_ep.sent_zlp = 0; + ep->dwc_ep.total_len = buflen; + + ep->dwc_ep.maxxfer = max_transfer; + if (GET_CORE_IF(pcd)->dma_desc_enable) { + uint32_t out_max_xfer = + DDMA_MAX_TRANSFER_SIZE - + (DDMA_MAX_TRANSFER_SIZE % 4); + if (ep->dwc_ep.is_in) { + if (ep->dwc_ep.maxxfer > + DDMA_MAX_TRANSFER_SIZE) { + ep->dwc_ep.maxxfer = + DDMA_MAX_TRANSFER_SIZE; + } + } else { + if (ep->dwc_ep.maxxfer > + out_max_xfer) { + ep->dwc_ep.maxxfer = + out_max_xfer; + } + } + } + if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) { + ep->dwc_ep.maxxfer -= + (ep->dwc_ep.maxxfer % + ep->dwc_ep.maxpacket); + } + + if (zero) { + if ((ep->dwc_ep.total_len % + ep->dwc_ep.maxpacket == 0) + && (ep->dwc_ep.total_len != 0)) { + ep->dwc_ep.sent_zlp = 1; + } + } +#ifdef DWC_UTE_CFI + } +#endif + dwc_otg_ep_start_transfer(GET_CORE_IF(pcd), + &ep->dwc_ep); + } + } + + if ((req != 0) || prevented) { + ++pcd->request_pending; + DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry); + if (ep->dwc_ep.is_in && ep->stopped + && !(GET_CORE_IF(pcd)->dma_enable)) { + /** @todo NGS Create a function for this. */ + diepmsk_data_t diepmsk = {.d32 = 0 }; + diepmsk.b.intktxfemp = 1; + if (GET_CORE_IF(pcd)->multiproc_int_enable) { + dwc_modify_reg32(&GET_CORE_IF(pcd)->dev_if-> + dev_global_regs-> + diepeachintmsk[ep->dwc_ep.num], + 0, diepmsk.d32); + } else { + dwc_modify_reg32(&GET_CORE_IF(pcd)->dev_if-> + dev_global_regs->diepmsk, 0, + diepmsk.d32); + } + + } + } + + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); + + return 0; +} +int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle, + void *req_handle) +{ + uint64_t flags; + dwc_otg_pcd_request_t *req; + dwc_otg_pcd_ep_t *ep; + + ep = get_ep_from_handle(pcd, ep_handle); + if (!ep->desc && ep->dwc_ep.num != 0) { + DWC_WARN("bad argument\n"); + return -DWC_E_INVALID; + } + + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); + + /* make sure it's actually queued on this endpoint */ + DWC_CIRCLEQ_FOREACH(req, &ep->queue, queue_entry) { + if (req->priv == (void *)req_handle) { + break; + } + } + + if (req->priv != (void *)req_handle) { + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); + return -DWC_E_INVALID; + } + + if (!DWC_CIRCLEQ_EMPTY_ENTRY(req, queue_entry)) { + dwc_otg_request_done(ep, req, -DWC_E_RESTART); + } else { + req = 0; + } + + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); + + return req ? 0 : -DWC_E_SHUTDOWN; + +} + +/** + * dwc_otg_pcd_ep_wedge - sets the halt feature and ignores clear requests + * + * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT) + * requests. If the gadget driver clears the halt status, it will + * automatically unwedge the endpoint. + * + * Returns zero on success, else negative DWC error code. + */ +int dwc_otg_pcd_ep_wedge(dwc_otg_pcd_t * pcd, void *ep_handle) +{ + dwc_otg_pcd_ep_t *ep; + uint64_t flags; + int retval = 0; + + ep = get_ep_from_handle(pcd, ep_handle); + + if ((!ep->desc && ep != &pcd->ep0) || + (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) { + DWC_WARN("%s, bad ep\n", __func__); + return -DWC_E_INVALID; + } + + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) { + DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num, + ep->dwc_ep.is_in ? "IN" : "OUT"); + retval = -DWC_E_AGAIN; + } else { + /* This code needs to be reviewed */ + if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) { + dtxfsts_data_t txstatus; + fifosize_data_t txfifosize; + + txfifosize.d32 = + dwc_read_reg32(&GET_CORE_IF(pcd)->core_global_regs-> + dptxfsiz_dieptxf[ep->dwc_ep. + tx_fifo_num]); + txstatus.d32 = + dwc_read_reg32(&GET_CORE_IF(pcd)->dev_if-> + in_ep_regs[ep->dwc_ep.num]->dtxfsts); + + if (txstatus.b.txfspcavail < txfifosize.b.depth) { + DWC_WARN("%s() Data In Tx Fifo\n", __func__); + retval = -DWC_E_AGAIN; + } else { + if (ep->dwc_ep.num == 0) { + pcd->ep0state = EP0_STALL; + } + + ep->stopped = 1; + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), + &ep->dwc_ep); + } + } else { + if (ep->dwc_ep.num == 0) { + pcd->ep0state = EP0_STALL; + } + + ep->stopped = 1; + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep); + } + } + + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); + + return retval; +} + +int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value) +{ + dwc_otg_pcd_ep_t *ep; + uint64_t flags; + int retval = 0; + + ep = get_ep_from_handle(pcd, ep_handle); + + if ((!ep->desc && ep != &pcd->ep0) || + (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) { + DWC_WARN("%s, bad ep\n", __func__); + return -DWC_E_INVALID; + } + + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) { + DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num, + ep->dwc_ep.is_in ? "IN" : "OUT"); + retval = -DWC_E_AGAIN; + } else if (value == 0) { + dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep); + } else if (value == 1) { + if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) { + dtxfsts_data_t txstatus; + fifosize_data_t txfifosize; + + txfifosize.d32 = + dwc_read_reg32(&GET_CORE_IF(pcd)->core_global_regs-> + dptxfsiz_dieptxf[ep->dwc_ep. + tx_fifo_num]); + txstatus.d32 = + dwc_read_reg32(&GET_CORE_IF(pcd)->dev_if-> + in_ep_regs[ep->dwc_ep.num]->dtxfsts); + + if (txstatus.b.txfspcavail < txfifosize.b.depth) { + DWC_WARN("%s() Data In Tx Fifo\n", __func__); + retval = -DWC_E_AGAIN; + } else { + if (ep->dwc_ep.num == 0) { + pcd->ep0state = EP0_STALL; + } + + ep->stopped = 1; + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), + &ep->dwc_ep); + } + } else { + if (ep->dwc_ep.num == 0) { + pcd->ep0state = EP0_STALL; + } + + ep->stopped = 1; + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep); + } + } else if (value == 2) { + ep->dwc_ep.stall_clear_flag = 0; + } else if (value == 3) { + ep->dwc_ep.stall_clear_flag = 1; + } + + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); + + return retval; +} + +/** + * This function initiates remote wakeup of the host from suspend state. + */ +void dwc_otg_pcd_rem_wkup_from_suspend(dwc_otg_pcd_t * pcd, int set) +{ + dctl_data_t dctl = { 0 }; + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); + dsts_data_t dsts; + + dsts.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts); + if (!dsts.b.suspsts) { + DWC_WARN("Remote wakeup while is not in suspend state\n"); + } + /* Check if DEVICE_REMOTE_WAKEUP feature enabled */ + if (pcd->remote_wakeup_enable) { + if (set) { + dctl.b.rmtwkupsig = 1; + dwc_modify_reg32(&core_if->dev_if->dev_global_regs-> + dctl, 0, dctl.d32); + DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n"); + dwc_mdelay(2); + dwc_modify_reg32(&core_if->dev_if->dev_global_regs-> + dctl, dctl.d32, 0); + DWC_DEBUGPL(DBG_PCD, "Clear Remote Wakeup\n"); + } + } else { + DWC_DEBUGPL(DBG_PCD, "Remote Wakeup is disabled\n"); + } +} + +#ifdef CONFIG_USB_DWC_OTG_LPM +/** + * This function initiates remote wakeup of the host from L1 sleep state. + */ +void dwc_otg_pcd_rem_wkup_from_sleep(dwc_otg_pcd_t * pcd, int set) +{ + glpmcfg_data_t lpmcfg; + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); + + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg); + + /* Check if we are in L1 state */ + if (!lpmcfg.b.prt_sleep_sts) { + DWC_DEBUGPL(DBG_PCD, "Device is not in sleep state\n"); + return; + } + + /* Check if host allows remote wakeup */ + if (!lpmcfg.b.rem_wkup_en) { + DWC_DEBUGPL(DBG_PCD, "Host does not allow remote wakeup\n"); + return; + } + + /* Check if Resume OK */ + if (!lpmcfg.b.sleep_state_resumeok) { + DWC_DEBUGPL(DBG_PCD, "Sleep state resume is not OK\n"); + return; + } + + lpmcfg.d32 = dwc_read_reg32(&core_if->core_global_regs->glpmcfg); + lpmcfg.b.en_utmi_sleep = 0; + lpmcfg.b.hird_thres &= (~(1 << 4)); + dwc_write_reg32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32); + + if (set) { + dctl_data_t dctl = {.d32 = 0 }; + dctl.b.rmtwkupsig = 1; + /* Set RmtWkUpSig bit to start remote wakup signaling. + * Hardware will automatically clear this bit. + */ + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->dctl, + 0, dctl.d32); + DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n"); + } + +} +#endif + +/** + * Performs remote wakeup. + */ +void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set) +{ + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); + if (dwc_otg_is_device_mode(core_if)) { +#ifdef CONFIG_USB_DWC_OTG_LPM + if (core_if->lx_state == DWC_OTG_L1) { + dwc_otg_pcd_rem_wkup_from_sleep(pcd, set); + } else { +#endif + dwc_otg_pcd_rem_wkup_from_suspend(pcd, set); +#ifdef CONFIG_USB_DWC_OTG_LPM + } +#endif + } + return; +} + +int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd) +{ + dsts_data_t dsts; + gotgctl_data_t gotgctl; + uint64_t flags; + + DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); + + /* + * This function starts the Protocol if no session is in progress. If + * a session is already in progress, but the device is suspended, + * remote wakeup signaling is started. + */ + + /* Check if valid session */ + gotgctl.d32 = + dwc_read_reg32(&(GET_CORE_IF(pcd)->core_global_regs->gotgctl)); + if (gotgctl.b.bsesvld) { + /* Check if suspend state */ + dsts.d32 = + dwc_read_reg32(& + (GET_CORE_IF(pcd)->dev_if->dev_global_regs-> + dsts)); + if (dsts.b.suspsts) { + dwc_otg_pcd_remote_wakeup(pcd, 1); + } + } else { + dwc_otg_pcd_initiate_srp(pcd); + } + + DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); + return 0; + +} + +/** + * Start the SRP timer to detect when the SRP does not complete within + * 6 seconds. + * + * @param pcd the pcd structure. + */ +void dwc_otg_pcd_start_srp_timer(dwc_otg_pcd_t * pcd) +{ + GET_CORE_IF(pcd)->srp_timer_started = 1; + DWC_TIMER_SCHEDULE(pcd->srp_timer, 6000 /* 6 secs */ ); +} + +void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd) +{ + uint32_t *addr = + (uint32_t *) & (GET_CORE_IF(pcd)->core_global_regs->gotgctl); + gotgctl_data_t mem; + gotgctl_data_t val; + + val.d32 = dwc_read_reg32(addr); + if (val.b.sesreq) { + DWC_ERROR("Session Request Already active!\n"); + return; + } + + DWC_INFO("Session Request Initated\n"); //NOTICE + mem.d32 = dwc_read_reg32(addr); + mem.b.sesreq = 1; + dwc_write_reg32(addr, mem.d32); + + /* Start the SRP timer */ + dwc_otg_pcd_start_srp_timer(pcd); + return; +} + +int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd) +{ + return dwc_otg_get_frame_number(GET_CORE_IF(pcd)); +} + +int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd) +{ + return GET_CORE_IF(pcd)->core_params->lpm_enable; +} + +uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd) +{ + return pcd->b_hnp_enable; +} + +uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd) +{ + return pcd->a_hnp_support; +} + +uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd) +{ + return pcd->a_alt_hnp_support; +} + +int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd) +{ + return pcd->remote_wakeup_enable; +} + +#endif /* DWC_HOST_ONLY */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd.h b/drivers/usb/host/dwc_otg/dwc_otg_pcd.h new file mode 100644 index 000000000000..d38e16941ac5 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd.h @@ -0,0 +1,216 @@ +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.h $ + * $Revision: #39 $ + * $Date: 2008/12/16 $ + * $Change: 1153731 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ +#ifndef DWC_HOST_ONLY +#if !defined(__DWC_PCD_H__) +#define __DWC_PCD_H__ + +#include "usb.h" +#include "dwc_otg_cil.h" +#include "dwc_otg_pcd_if.h" +struct cfiobject; + +/** + * @file + * + * This file contains the structures, constants, and interfaces for + * the Perpherial Contoller Driver (PCD). + * + * The Peripheral Controller Driver (PCD) for Linux will implement the + * Gadget API, so that the existing Gadget drivers can be used. For + * the Mass Storage Function driver the File-backed USB Storage Gadget + * (FBS) driver will be used. The FBS driver supports the + * Control-Bulk (CB), Control-Bulk-Interrupt (CBI), and Bulk-Only + * transports. + * + */ + +/** Max Transfer size for any EP */ +#define DDMA_MAX_TRANSFER_SIZE 65535 + +/** Max DMA Descriptor count for any EP */ +#define MAX_DMA_DESC_CNT 64 + +/** + * Get the pointer to the core_if from the pcd pointer. + */ +#define GET_CORE_IF( _pcd ) (_pcd->core_if) + +/** + * States of EP0. + */ +typedef enum ep0_state { + EP0_DISCONNECT, /* no host */ + EP0_IDLE, + EP0_IN_DATA_PHASE, + EP0_OUT_DATA_PHASE, + EP0_IN_STATUS_PHASE, + EP0_OUT_STATUS_PHASE, + EP0_STALL, +} ep0state_e; + +/** Fordward declaration.*/ +struct dwc_otg_pcd; + +/** DWC_otg iso request structure. + * + */ +typedef struct usb_iso_request dwc_otg_pcd_iso_request_t; + +/** DWC_otg request structure. + * This structure is a list of requests. + */ +typedef struct dwc_otg_pcd_request { + void *priv; + void *buf; + dwc_dma_t dma; + uint32_t length; + uint32_t actual; + unsigned sent_zlp:1; + + DWC_CIRCLEQ_ENTRY(dwc_otg_pcd_request) queue_entry; +} dwc_otg_pcd_request_t; + +DWC_CIRCLEQ_HEAD(req_list, dwc_otg_pcd_request); + +/** PCD EP structure. + * This structure describes an EP, there is an array of EPs in the PCD + * structure. + */ +typedef struct dwc_otg_pcd_ep { + /** USB EP Descriptor */ + const usb_endpoint_descriptor_t *desc; + + /** queue of dwc_otg_pcd_requests. */ + struct req_list queue; + unsigned stopped:1; + unsigned disabling:1; + unsigned dma:1; + unsigned queue_sof:1; + +#ifdef DWC_EN_ISOC + /** ISOC req handle passed */ + void *iso_req_handle; +#endif //_EN_ISOC_ + + /** DWC_otg ep data. */ + dwc_ep_t dwc_ep; + + /** Pointer to PCD */ + struct dwc_otg_pcd *pcd; + + void *priv; +} dwc_otg_pcd_ep_t; + +/** DWC_otg PCD Structure. + * This structure encapsulates the data for the dwc_otg PCD. + */ +struct dwc_otg_pcd { + const struct dwc_otg_pcd_function_ops *fops; + /** Core Interface */ + dwc_otg_core_if_t *core_if; + /** State of EP0 */ + ep0state_e ep0state; + /** EP0 Request is pending */ + unsigned ep0_pending:1; + /** Indicates when SET CONFIGURATION Request is in process */ + unsigned request_config:1; + /** The state of the Remote Wakeup Enable. */ + unsigned remote_wakeup_enable:1; + /** The state of the B-Device HNP Enable. */ + unsigned b_hnp_enable:1; + /** The state of A-Device HNP Support. */ + unsigned a_hnp_support:1; + /** The state of the A-Device Alt HNP support. */ + unsigned a_alt_hnp_support:1; + /** Count of pending Requests */ + unsigned request_pending; + + /** SETUP packet for EP0 + * This structure is allocated as a DMA buffer on PCD initialization + * with enough space for up to 3 setup packets. + */ + union { + usb_device_request_t req; + uint32_t d32[2]; + } *setup_pkt; + + dwc_dma_t setup_pkt_dma_handle; + + /** 2-byte dma buffer used to return status from GET_STATUS */ + uint16_t *status_buf; + dwc_dma_t status_buf_dma_handle; + + /** EP0 */ + dwc_otg_pcd_ep_t ep0; + + /** Array of IN EPs. */ + dwc_otg_pcd_ep_t in_ep[MAX_EPS_CHANNELS - 1]; + /** Array of OUT EPs. */ + dwc_otg_pcd_ep_t out_ep[MAX_EPS_CHANNELS - 1]; + /** number of valid EPs in the above array. */ +// unsigned num_eps : 4; + dwc_spinlock_t *lock; + /** Timer for SRP. If it expires before SRP is successful + * clear the SRP. */ + dwc_timer_t *srp_timer; + + /** Tasklet to defer starting of TEST mode transmissions until + * Status Phase has been completed. + */ + dwc_tasklet_t *test_mode_tasklet; + + /** Tasklet to delay starting of xfer in DMA mode */ + dwc_tasklet_t *start_xfer_tasklet; + + /** The test mode to enter when the tasklet is executed. */ + unsigned test_mode; + /** The cfi_api structure that implements most of the CFI API + * and OTG specific core configuration functionality + */ +#ifdef DWC_UTE_CFI + struct cfiobject *cfi; +#endif + +}; + +//FIXME this functions should be static, and this prototypes should be removed +extern void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep); +extern void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep, + dwc_otg_pcd_request_t * req, int32_t status); + +void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep, + void *req_handle); + +extern void do_test_mode(void *data); +#endif +#endif /* DWC_HOST_ONLY */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h b/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h new file mode 100644 index 000000000000..66e9db78ccc4 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h @@ -0,0 +1,333 @@ +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_if.h $ + * $Revision: #6 $ + * $Date: 2009/04/03 $ + * $Change: 1225059 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ +#ifndef DWC_HOST_ONLY + +#if !defined(__DWC_PCD_IF_H__) +#define __DWC_PCD_IF_H__ + +#include "dwc_os.h" +#include "dwc_otg_core_if.h" + +/** @file + * This file defines DWC_OTG PCD Core API. + */ + +struct dwc_otg_pcd; +typedef struct dwc_otg_pcd dwc_otg_pcd_t; + +/** Maxpacket size for EP0 */ +#define MAX_EP0_SIZE 64 +/** Maxpacket size for any EP */ +#define MAX_PACKET_SIZE 1024 + +/** @name Function Driver Callbacks */ +/** @{ */ + +/** This function will be called whenever a previously queued request has + * completed. The status value will be set to -DWC_E_SHUTDOWN to indicated a + * failed or aborted transfer, or -DWC_E_RESTART to indicate the device was reset, + * or -DWC_E_TIMEOUT to indicate it timed out, or -DWC_E_INVALID to indicate invalid + * parameters. */ +typedef int (*dwc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle, + void *req_handle, int32_t status, + uint32_t actual); +/** + * This function will be called whenever a previousle queued ISOC request has + * completed. Count of ISOC packets could be read using dwc_otg_pcd_get_iso_packet_count + * function. + * The status of each ISOC packet could be read using dwc_otg_pcd_get_iso_packet_* + * functions. + */ +typedef int (*dwc_isoc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle, + void *req_handle, int proc_buf_num); +/** This function should handle any SETUP request that cannot be handled by the + * PCD Core. This includes most GET_DESCRIPTORs, SET_CONFIGS, Any + * class-specific requests, etc. The function must non-blocking. + * + * Returns 0 on success. + * Returns -DWC_E_NOT_SUPPORTED if the request is not supported. + * Returns -DWC_E_INVALID if the setup request had invalid parameters or bytes. + * Returns -DWC_E_SHUTDOWN on any other error. */ +typedef int (*dwc_setup_cb_t) (dwc_otg_pcd_t * pcd, uint8_t * bytes); +/** This is called whenever the device has been disconnected. The function + * driver should take appropriate action to clean up all pending requests in the + * PCD Core, remove all endpoints (except ep0), and initialize back to reset + * state. */ +typedef int (*dwc_disconnect_cb_t) (dwc_otg_pcd_t * pcd); +/** This function is called when device has been connected. */ +typedef int (*dwc_connect_cb_t) (dwc_otg_pcd_t * pcd, int speed); +/** This function is called when device has been suspended */ +typedef int (*dwc_suspend_cb_t) (dwc_otg_pcd_t * pcd); +/** This function is called when device has received LPM tokens, i.e. + * device has been sent to sleep state. */ +typedef int (*dwc_sleep_cb_t) (dwc_otg_pcd_t * pcd); +/** This function is called when device has been resumed + * from suspend(L2) or L1 sleep state. */ +typedef int (*dwc_resume_cb_t) (dwc_otg_pcd_t * pcd); +/** This function is called whenever hnp params has been changed. + * User can call get_b_hnp_enable, get_a_hnp_support, get_a_alt_hnp_support functions + * to get hnp parameters. */ +typedef int (*dwc_hnp_params_changed_cb_t) (dwc_otg_pcd_t * pcd); +/** This function is called whenever USB RESET is detected. */ +typedef int (*dwc_reset_cb_t) (dwc_otg_pcd_t * pcd); + +typedef int (*cfi_setup_cb_t) (dwc_otg_pcd_t * pcd, void *ctrl_req_bytes); + +/** Function Driver Ops Data Structure */ +struct dwc_otg_pcd_function_ops { + dwc_connect_cb_t connect; + dwc_disconnect_cb_t disconnect; + dwc_setup_cb_t setup; + dwc_completion_cb_t complete; + dwc_isoc_completion_cb_t isoc_complete; + dwc_suspend_cb_t suspend; + dwc_sleep_cb_t sleep; + dwc_resume_cb_t resume; + dwc_reset_cb_t reset; + dwc_hnp_params_changed_cb_t hnp_changed; + cfi_setup_cb_t cfi_setup; +}; +/** @} */ + +/** @name Function Driver Functions */ +/** @{ */ + +/** Call this function to get pointer on dwc_otg_pcd_t, + * this pointer will be used for all PCD API functions. + * + * @param core_if The DWC_OTG Core + */ +extern dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if); + +/** Frees PCD allocated by dwc_otg_pcd_init + * + * @param pcd The PCD + */ +extern void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd); + +/** Call this to bind the function driver to the PCD Core. + * + * @param pcd Pointer on dwc_otg_pcd_t returned by dwc_otg_pcd_init function. + * @param fops The Function Driver Ops data structure containing pointers to all callbacks. + */ +extern void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd, + const struct dwc_otg_pcd_function_ops *fops); + +/** Enables an endpoint for use. This function enables an endpoint in + * the PCD. The endpoint is described by the ep_desc which has the + * same format as a USB ep descriptor. The ep_handle parameter is used to refer + * to the endpoint from other API functions and in callbacks. Normally this + * should be called after a SET_CONFIGURATION/SET_INTERFACE to configure the + * core for that interface. + * + * Returns -DWC_E_INVALID if invalid parameters were passed. + * Returns -DWC_E_SHUTDOWN if any other error ocurred. + * Returns 0 on success. + * + * @param pcd The PCD + * @param ep_desc Endpoint descriptor + * @param ep_handle Handle on endpoint, that will be used to identify endpoint. + */ +extern int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd, + const uint8_t * ep_desc, void *ep_handle); + +/** Disable the endpoint referenced by ep_handle. + * + * Returns -DWC_E_INVALID if invalid parameters were passed. + * Returns -DWC_E_SHUTDOWN if any other error ocurred. + * Returns 0 on success. */ +extern int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle); + +/** Queue a data transfer request on the endpoint referenced by ep_handle. + * After the transfer is completes, the complete callback will be called with + * the request status. + * + * @param pcd The PCD + * @param ep_handle The handle of the endpoint + * @param buf The buffer for the data + * @param dma_buf The DMA buffer for the data + * @param buflen The length of the data transfer + * @param zero Specifies whether to send zero length last packet. + * @param req_handle Set this handle to any value to use to reference this + * request in the ep_dequeue function or from the complete callback + * @param atomic_alloc If driver need to perform atomic allocations + * for internal data structures. + * + * Returns -DWC_E_INVALID if invalid parameters were passed. + * Returns -DWC_E_SHUTDOWN if any other error ocurred. + * Returns 0 on success. */ +extern int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle, + uint8_t * buf, dwc_dma_t dma_buf, + uint32_t buflen, int zero, void *req_handle, + int atomic_alloc); + +/** De-queue the specified data transfer that has not yet completed. + * + * Returns -DWC_E_INVALID if invalid parameters were passed. + * Returns -DWC_E_SHUTDOWN if any other error ocurred. + * Returns 0 on success. */ +extern int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle, + void *req_handle); + +/** Halt (STALL) an endpoint or clear it. + * + * Returns -DWC_E_INVALID if invalid parameters were passed. + * Returns -DWC_E_SHUTDOWN if any other error ocurred. + * Returns -DWC_E_AGAIN if the STALL cannot be sent and must be tried again later + * Returns 0 on success. */ +extern int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value); + +/** This function */ +extern int dwc_otg_pcd_ep_wedge(dwc_otg_pcd_t * pcd, void *ep_handle); + +/** This function should be called on every hardware interrupt */ +extern int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd); + +/** This function returns current frame number */ +extern int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd); + +/** + * Start isochronous transfers on the endpoint referenced by ep_handle. + * For isochronous transfers duble buffering is used. + * After processing each of buffers comlete callback will be called with + * status for each transaction. + * + * @param pcd The PCD + * @param ep_handle The handle of the endpoint + * @param buf0 The virtual address of first data buffer + * @param buf1 The virtual address of second data buffer + * @param dma0 The DMA address of first data buffer + * @param dma1 The DMA address of second data buffer + * @param sync_frame Data pattern frame number + * @param dp_frame Data size for pattern frame + * @param data_per_frame Data size for regular frame + * @param start_frame Frame number to start transfers, if -1 then start transfers ASAP. + * @param buf_proc_intrvl Interval of ISOC Buffer processing + * @param req_handle Handle of ISOC request + * @param atomic_alloc Specefies whether to perform atomic allocation for + * internal data structures. + * + * Returns -DWC_E_NO_MEMORY if there is no enough memory. + * Returns -DWC_E_INVALID if incorrect arguments are passed to the function. + * Returns -DW_E_SHUTDOWN for any other error. + * Returns 0 on success + */ +extern int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle, + uint8_t * buf0, uint8_t * buf1, + dwc_dma_t dma0, dwc_dma_t dma1, + int sync_frame, int dp_frame, + int data_per_frame, int start_frame, + int buf_proc_intrvl, void *req_handle, + int atomic_alloc); + +/** Stop ISOC transfers on endpoint referenced by ep_handle. + * + * @param pcd The PCD + * @param ep_handle The handle of the endpoint + * @param req_handle Handle of ISOC request + * + * Returns -DWC_E_INVALID if incorrect arguments are passed to the function + * Returns 0 on success + */ +int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle, + void *req_handle); + +/** Get ISOC packet status. + * + * @param pcd The PCD + * @param ep_handle The handle of the endpoint + * @param iso_req_handle Isochronoush request handle + * @param packet Number of packet + * @param status Out parameter for returning status + * @param actual Out parameter for returning actual length + * @param offset Out parameter for returning offset + * + */ +extern void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd, + void *ep_handle, + void *iso_req_handle, int packet, + int *status, int *actual, + int *offset); + +/** Get ISOC packet count. + * + * @param pcd The PCD + * @param ep_handle The handle of the endpoint + * @param iso_req_handle + */ +extern int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd, + void *ep_handle, + void *iso_req_handle); + +/** This function starts the SRP Protocol if no session is in progress. If + * a session is already in progress, but the device is suspended, + * remote wakeup signaling is started. + */ +extern int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd); + +/** This function returns 1 if LPM support is enabled, and 0 otherwise. */ +extern int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd); + +/** This function returns 1 if remote wakeup is allowed and 0, otherwise. */ +extern int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd); + +/** Initiate SRP */ +extern void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd); + +/** Starts remote wakeup signaling. */ +extern void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set); + +/** This function returns whether device is dualspeed.*/ +extern uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd); + +/** This function returns whether device is otg. */ +extern uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd); + +/** These functions allow to get hnp parameters */ +extern uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd); +extern uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd); +extern uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd); + +/** CFI specific Interface functions */ +/** Allocate a cfi buffer */ +extern uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, + dwc_dma_t * addr, size_t buflen, + int flags); + +/******************************************************************************/ + +/** @} */ + +#endif /* __DWC_PCD_IF_H__ */ + +#endif /* DWC_HOST_ONLY */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c new file mode 100644 index 000000000000..f89e878eedbf --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c @@ -0,0 +1,4077 @@ +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_intr.c $ + * $Revision: #93 $ + * $Date: 2009/04/02 $ + * $Change: 1224216 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ +#ifndef DWC_HOST_ONLY + +#include "dwc_otg_pcd.h" + +#ifdef DWC_UTE_CFI +#include "dwc_otg_cfi.h" +#endif + +//#define PRINT_CFI_DMA_DESCS + +#define DEBUG_EP0 + +/** + * This function updates OTG. + */ +static void dwc_otg_pcd_update_otg(dwc_otg_pcd_t * pcd, const unsigned reset) +{ + + if (reset) { + pcd->b_hnp_enable = 0; + pcd->a_hnp_support = 0; + pcd->a_alt_hnp_support = 0; + } + + if (pcd->fops->hnp_changed) { + pcd->fops->hnp_changed(pcd); + } +} + +/** @file + * This file contains the implementation of the PCD Interrupt handlers. + * + * The PCD handles the device interrupts. Many conditions can cause a + * device interrupt. When an interrupt occurs, the device interrupt + * service routine determines the cause of the interrupt and + * dispatches handling to the appropriate function. These interrupt + * handling functions are described below. + * All interrupt registers are processed from LSB to MSB. + */ + +/** + * This function prints the ep0 state for debug purposes. + */ +static inline void print_ep0_state(dwc_otg_pcd_t * pcd) +{ +#ifdef DEBUG + char str[40]; + + switch (pcd->ep0state) { + case EP0_DISCONNECT: + dwc_strcpy(str, "EP0_DISCONNECT"); + break; + case EP0_IDLE: + dwc_strcpy(str, "EP0_IDLE"); + break; + case EP0_IN_DATA_PHASE: + dwc_strcpy(str, "EP0_IN_DATA_PHASE"); + break; + case EP0_OUT_DATA_PHASE: + dwc_strcpy(str, "EP0_OUT_DATA_PHASE"); + break; + case EP0_IN_STATUS_PHASE: + dwc_strcpy(str, "EP0_IN_STATUS_PHASE"); + break; + case EP0_OUT_STATUS_PHASE: + dwc_strcpy(str, "EP0_OUT_STATUS_PHASE"); + break; + case EP0_STALL: + dwc_strcpy(str, "EP0_STALL"); + break; + default: + dwc_strcpy(str, "EP0_INVALID"); + } + + DWC_DEBUGPL(DBG_ANY, "%s(%d)\n", str, pcd->ep0state); +#endif +} + +#ifdef DWC_UTE_CFI +static inline void print_desc(struct dwc_otg_dma_desc *ddesc, + const uint8_t * epname, int descnum) +{ + CFI_INFO + ("%s DMA_DESC(%d) buf=0x%08x bytes=0x%04x; sp=0x%x; l=0x%x; sts=0x%02x; bs=0x%02x\n", + epname, descnum, ddesc->buf, ddesc->status.b.bytes, + ddesc->status.b.sp, ddesc->status.b.l, ddesc->status.b.sts, + ddesc->status.b.bs); +} +#endif + +/** + * This function returns pointer to in ep struct with number ep_num + */ +static inline dwc_otg_pcd_ep_t *get_in_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num) +{ + int i; + int num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps; + if (ep_num == 0) { + return &pcd->ep0; + } else { + for (i = 0; i < num_in_eps; ++i) { + if (pcd->in_ep[i].dwc_ep.num == ep_num) + return &pcd->in_ep[i]; + } + return 0; + } +} + +/** + * This function returns pointer to out ep struct with number ep_num + */ +static inline dwc_otg_pcd_ep_t *get_out_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num) +{ + int i; + int num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps; + if (ep_num == 0) { + return &pcd->ep0; + } else { + for (i = 0; i < num_out_eps; ++i) { + if (pcd->out_ep[i].dwc_ep.num == ep_num) + return &pcd->out_ep[i]; + } + return 0; + } +} + +/** + * This functions gets a pointer to an EP from the wIndex address + * value of the control request. + */ +dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex) +{ + dwc_otg_pcd_ep_t *ep; + uint32_t ep_num = UE_GET_ADDR(wIndex); + + if (ep_num == 0) { + ep = &pcd->ep0; + } else if (UE_GET_DIR(wIndex) == UE_DIR_IN) { /* in ep */ + ep = &pcd->in_ep[ep_num - 1]; + } else { + ep = &pcd->out_ep[ep_num - 1]; + } + + return ep; +} + +/** + * This function checks the EP request queue, if the queue is not + * empty the next request is started. + */ +void start_next_request(dwc_otg_pcd_ep_t * ep) +{ + dwc_otg_pcd_request_t *req = 0; + uint32_t max_transfer = + GET_CORE_IF(ep->pcd)->core_params->max_transfer_size; + +#ifdef DWC_UTE_CFI + struct dwc_otg_pcd *pcd; + pcd = ep->pcd; +#endif + + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) { + req = DWC_CIRCLEQ_FIRST(&ep->queue); + +#ifdef DWC_UTE_CFI + if (ep->dwc_ep.buff_mode != BM_STANDARD) { + ep->dwc_ep.cfi_req_len = req->length; + pcd->cfi->ops.build_descriptors(pcd->cfi, pcd, ep, req); + } else { +#endif + /* Setup and start the Transfer */ + ep->dwc_ep.dma_addr = req->dma; + ep->dwc_ep.start_xfer_buff = req->buf; + ep->dwc_ep.xfer_buff = req->buf; + ep->dwc_ep.sent_zlp = 0; + ep->dwc_ep.total_len = req->length; + ep->dwc_ep.xfer_len = 0; + ep->dwc_ep.xfer_count = 0; + + ep->dwc_ep.maxxfer = max_transfer; + if (GET_CORE_IF(ep->pcd)->dma_desc_enable) { + uint32_t out_max_xfer = DDMA_MAX_TRANSFER_SIZE + - (DDMA_MAX_TRANSFER_SIZE % 4); + if (ep->dwc_ep.is_in) { + if (ep->dwc_ep.maxxfer > + DDMA_MAX_TRANSFER_SIZE) { + ep->dwc_ep.maxxfer = + DDMA_MAX_TRANSFER_SIZE; + } + } else { + if (ep->dwc_ep.maxxfer > out_max_xfer) { + ep->dwc_ep.maxxfer = + out_max_xfer; + } + } + } + if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) { + ep->dwc_ep.maxxfer -= + (ep->dwc_ep.maxxfer % ep->dwc_ep.maxpacket); + } + if (req->sent_zlp) { + if ((ep->dwc_ep.total_len % + ep->dwc_ep.maxpacket == 0) + && (ep->dwc_ep.total_len != 0)) { + ep->dwc_ep.sent_zlp = 1; + } + + } +#ifdef DWC_UTE_CFI + } +#endif + dwc_otg_ep_start_transfer(GET_CORE_IF(ep->pcd), &ep->dwc_ep); + } +} + +/** + * This function handles the SOF Interrupts. At this time the SOF + * Interrupt is disabled. + */ +int32_t dwc_otg_pcd_handle_sof_intr(dwc_otg_pcd_t * pcd) +{ + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); + + gintsts_data_t gintsts; + + DWC_DEBUGPL(DBG_PCD, "SOF\n"); + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.sofintr = 1; + dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32); + + return 1; +} + +/** + * This function handles the Rx Status Queue Level Interrupt, which + * indicates that there is a least one packet in the Rx FIFO. The + * packets are moved from the FIFO to memory, where they will be + * processed when the Endpoint Interrupt Register indicates Transfer + * Complete or SETUP Phase Done. + * + * Repeat the following until the Rx Status Queue is empty: + * -# Read the Receive Status Pop Register (GRXSTSP) to get Packet + * info + * -# If Receive FIFO is empty then skip to step Clear the interrupt + * and exit + * -# If SETUP Packet call dwc_otg_read_setup_packet to copy the + * SETUP data to the buffer + * -# If OUT Data Packet call dwc_otg_read_packet to copy the data + * to the destination buffer + */ +int32_t dwc_otg_pcd_handle_rx_status_q_level_intr(dwc_otg_pcd_t * pcd) +{ + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; + gintmsk_data_t gintmask = {.d32 = 0 }; + device_grxsts_data_t status; + dwc_otg_pcd_ep_t *ep; + gintsts_data_t gintsts; +#ifdef DEBUG + static char *dpid_str[] = { "D0", "D2", "D1", "MDATA" }; +#endif + + //DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _pcd); + /* Disable the Rx Status Queue Level interrupt */ + gintmask.b.rxstsqlvl = 1; + dwc_modify_reg32(&global_regs->gintmsk, gintmask.d32, 0); + + /* Get the Status from the top of the FIFO */ + status.d32 = dwc_read_reg32(&global_regs->grxstsp); + + DWC_DEBUGPL(DBG_PCD, "EP:%d BCnt:%d DPID:%s " + "pktsts:%x Frame:%d(0x%0x)\n", + status.b.epnum, status.b.bcnt, + dpid_str[status.b.dpid], + status.b.pktsts, status.b.fn, status.b.fn); + /* Get pointer to EP structure */ + ep = get_out_ep(pcd, status.b.epnum); + + switch (status.b.pktsts) { + case DWC_DSTS_GOUT_NAK: + DWC_DEBUGPL(DBG_PCDV, "Global OUT NAK\n"); + break; + case DWC_STS_DATA_UPDT: + DWC_DEBUGPL(DBG_PCDV, "OUT Data Packet\n"); + if (status.b.bcnt && ep->dwc_ep.xfer_buff) { + /** @todo NGS Check for buffer overflow? */ + dwc_otg_read_packet(core_if, + ep->dwc_ep.xfer_buff, + status.b.bcnt); + ep->dwc_ep.xfer_count += status.b.bcnt; + ep->dwc_ep.xfer_buff += status.b.bcnt; + } + break; + case DWC_STS_XFER_COMP: + DWC_DEBUGPL(DBG_PCDV, "OUT Complete\n"); + break; + case DWC_DSTS_SETUP_COMP: +#ifdef DEBUG_EP0 + DWC_DEBUGPL(DBG_PCDV, "Setup Complete\n"); +#endif + break; + case DWC_DSTS_SETUP_UPDT: + dwc_otg_read_setup_packet(core_if, pcd->setup_pkt->d32); +#ifdef DEBUG_EP0 + DWC_DEBUGPL(DBG_PCD, + "SETUP PKT: %02x.%02x v%04x i%04x l%04x\n", + pcd->setup_pkt->req.bmRequestType, + pcd->setup_pkt->req.bRequest, + UGETW(pcd->setup_pkt->req.wValue), + UGETW(pcd->setup_pkt->req.wIndex), + UGETW(pcd->setup_pkt->req.wLength)); +#endif + ep->dwc_ep.xfer_count += status.b.bcnt; + break; + default: + DWC_DEBUGPL(DBG_PCDV, "Invalid Packet Status (0x%0x)\n", + status.b.pktsts); + break; + } + + /* Enable the Rx Status Queue Level interrupt */ + dwc_modify_reg32(&global_regs->gintmsk, 0, gintmask.d32); + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.rxstsqlvl = 1; + dwc_write_reg32(&global_regs->gintsts, gintsts.d32); + + //DWC_DEBUGPL(DBG_PCDV, "EXIT: %s\n", __func__); + return 1; +} + +/** + * This function examines the Device IN Token Learning Queue to + * determine the EP number of the last IN token received. This + * implementation is for the Mass Storage device where there are only + * 2 IN EPs (Control-IN and BULK-IN). + * + * The EP numbers for the first six IN Tokens are in DTKNQR1 and there + * are 8 EP Numbers in each of the other possible DTKNQ Registers. + * + * @param core_if Programming view of DWC_otg controller. + * + */ +static inline int get_ep_of_last_in_token(dwc_otg_core_if_t * core_if) +{ + dwc_otg_device_global_regs_t *dev_global_regs = + core_if->dev_if->dev_global_regs; + const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth; + /* Number of Token Queue Registers */ + const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8; + dtknq1_data_t dtknqr1; + uint32_t in_tkn_epnums[4]; + int ndx = 0; + int i = 0; + volatile uint32_t *addr = &dev_global_regs->dtknqr1; + int epnum = 0; + + //DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH); + + /* Read the DTKNQ Registers */ + for (i = 0; i < DTKNQ_REG_CNT; i++) { + in_tkn_epnums[i] = dwc_read_reg32(addr); + DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1, + in_tkn_epnums[i]); + if (addr == &dev_global_regs->dvbusdis) { + addr = &dev_global_regs->dtknqr3_dthrctl; + } else { + ++addr; + } + + } + + /* Copy the DTKNQR1 data to the bit field. */ + dtknqr1.d32 = in_tkn_epnums[0]; + /* Get the EP numbers */ + in_tkn_epnums[0] = dtknqr1.b.epnums0_5; + ndx = dtknqr1.b.intknwptr - 1; + + //DWC_DEBUGPL(DBG_PCDV,"ndx=%d\n",ndx); + if (ndx == -1) { + /** @todo Find a simpler way to calculate the max + * queue position.*/ + int cnt = TOKEN_Q_DEPTH; + if (TOKEN_Q_DEPTH <= 6) { + cnt = TOKEN_Q_DEPTH - 1; + } else if (TOKEN_Q_DEPTH <= 14) { + cnt = TOKEN_Q_DEPTH - 7; + } else if (TOKEN_Q_DEPTH <= 22) { + cnt = TOKEN_Q_DEPTH - 15; + } else { + cnt = TOKEN_Q_DEPTH - 23; + } + epnum = (in_tkn_epnums[DTKNQ_REG_CNT - 1] >> (cnt * 4)) & 0xF; + } else { + if (ndx <= 5) { + epnum = (in_tkn_epnums[0] >> (ndx * 4)) & 0xF; + } else if (ndx <= 13) { + ndx -= 6; + epnum = (in_tkn_epnums[1] >> (ndx * 4)) & 0xF; + } else if (ndx <= 21) { + ndx -= 14; + epnum = (in_tkn_epnums[2] >> (ndx * 4)) & 0xF; + } else if (ndx <= 29) { + ndx -= 22; + epnum = (in_tkn_epnums[3] >> (ndx * 4)) & 0xF; + } + } + //DWC_DEBUGPL(DBG_PCD,"epnum=%d\n",epnum); + return epnum; +} + +/** + * This interrupt occurs when the non-periodic Tx FIFO is half-empty. + * The active request is checked for the next packet to be loaded into + * the non-periodic Tx FIFO. + */ +int32_t dwc_otg_pcd_handle_np_tx_fifo_empty_intr(dwc_otg_pcd_t * pcd) +{ + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; + dwc_otg_dev_in_ep_regs_t *ep_regs; + gnptxsts_data_t txstatus = {.d32 = 0 }; + gintsts_data_t gintsts; + + int epnum = 0; + dwc_otg_pcd_ep_t *ep = 0; + uint32_t len = 0; + int dwords; + + /* Get the epnum from the IN Token Learning Queue. */ + epnum = get_ep_of_last_in_token(core_if); + ep = get_in_ep(pcd, epnum); + + DWC_DEBUGPL(DBG_PCD, "NP TxFifo Empty: %d \n", epnum); + + ep_regs = core_if->dev_if->in_ep_regs[epnum]; + + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count; + if (len > ep->dwc_ep.maxpacket) { + len = ep->dwc_ep.maxpacket; + } + dwords = (len + 3) / 4; + + /* While there is space in the queue and space in the FIFO and + * More data to tranfer, Write packets to the Tx FIFO */ + txstatus.d32 = dwc_read_reg32(&global_regs->gnptxsts); + DWC_DEBUGPL(DBG_PCDV, "b4 GNPTXSTS=0x%08x\n", txstatus.d32); + + while (txstatus.b.nptxqspcavail > 0 && + txstatus.b.nptxfspcavail > dwords && + ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len) { + /* Write the FIFO */ + dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0); + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count; + + if (len > ep->dwc_ep.maxpacket) { + len = ep->dwc_ep.maxpacket; + } + + dwords = (len + 3) / 4; + txstatus.d32 = dwc_read_reg32(&global_regs->gnptxsts); + DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n", txstatus.d32); + } + + DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n", + dwc_read_reg32(&global_regs->gnptxsts)); + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.nptxfempty = 1; + dwc_write_reg32(&global_regs->gintsts, gintsts.d32); + + return 1; +} + +/** + * This function is called when dedicated Tx FIFO Empty interrupt occurs. + * The active request is checked for the next packet to be loaded into + * apropriate Tx FIFO. + */ +static int32_t write_empty_tx_fifo(dwc_otg_pcd_t * pcd, uint32_t epnum) +{ + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); + dwc_otg_dev_if_t *dev_if = core_if->dev_if; + dwc_otg_dev_in_ep_regs_t *ep_regs; + dtxfsts_data_t txstatus = {.d32 = 0 }; + dwc_otg_pcd_ep_t *ep = 0; + uint32_t len = 0; + int dwords; + + ep = get_in_ep(pcd, epnum); + + DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum); + + ep_regs = core_if->dev_if->in_ep_regs[epnum]; + + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count; + + if (len > ep->dwc_ep.maxpacket) { + len = ep->dwc_ep.maxpacket; + } + + dwords = (len + 3) / 4; + + /* While there is space in the queue and space in the FIFO and + * More data to tranfer, Write packets to the Tx FIFO */ + txstatus.d32 = dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dtxfsts); + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32); + + while (txstatus.b.txfspcavail > dwords && + ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len && + ep->dwc_ep.xfer_len != 0) { + /* Write the FIFO */ + dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0); + + len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count; + if (len > ep->dwc_ep.maxpacket) { + len = ep->dwc_ep.maxpacket; + } + + dwords = (len + 3) / 4; + txstatus.d32 = + dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dtxfsts); + DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum, + txstatus.d32); + } + + DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, + dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dtxfsts)); + + return 1; +} + +/** + * This function is called when the Device is disconnected. It stops + * any active requests and informs the Gadget driver of the + * disconnect. + */ +void dwc_otg_pcd_stop(dwc_otg_pcd_t * pcd) +{ + int i, num_in_eps, num_out_eps; + dwc_otg_pcd_ep_t *ep; + + gintmsk_data_t intr_mask = {.d32 = 0 }; + + DWC_SPINLOCK(pcd->lock); + + num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps; + num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps; + + DWC_DEBUGPL(DBG_PCDV, "%s() \n", __func__); + /* don't disconnect drivers more than once */ + if (pcd->ep0state == EP0_DISCONNECT) { + DWC_DEBUGPL(DBG_ANY, "%s() Already Disconnected\n", __func__); + return; + } + pcd->ep0state = EP0_DISCONNECT; + + /* Reset the OTG state. */ + dwc_otg_pcd_update_otg(pcd, 1); + + /* Disable the NP Tx Fifo Empty Interrupt. */ + intr_mask.b.nptxfempty = 1; + dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk, + intr_mask.d32, 0); + + /* Flush the FIFOs */ + /**@todo NGS Flush Periodic FIFOs */ + dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd), 0x10); + dwc_otg_flush_rx_fifo(GET_CORE_IF(pcd)); + + /* prevent new request submissions, kill any outstanding requests */ + ep = &pcd->ep0; + dwc_otg_request_nuke(ep); + /* prevent new request submissions, kill any outstanding requests */ + for (i = 0; i < num_in_eps; i++) { + dwc_otg_pcd_ep_t *ep = &pcd->in_ep[i]; + dwc_otg_request_nuke(ep); + } + /* prevent new request submissions, kill any outstanding requests */ + for (i = 0; i < num_out_eps; i++) { + dwc_otg_pcd_ep_t *ep = &pcd->out_ep[i]; + dwc_otg_request_nuke(ep); + } + + /* report disconnect; the driver is already quiesced */ + if (pcd->fops->disconnect) { + DWC_SPINUNLOCK(pcd->lock); + pcd->fops->disconnect(pcd); + DWC_SPINLOCK(pcd->lock); + } + DWC_SPINUNLOCK(pcd->lock); +} + +/** + * This interrupt indicates that ... + */ +int32_t dwc_otg_pcd_handle_i2c_intr(dwc_otg_pcd_t * pcd) +{ + gintmsk_data_t intr_mask = {.d32 = 0 }; + gintsts_data_t gintsts; + + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "i2cintr"); + intr_mask.b.i2cintr = 1; + dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk, + intr_mask.d32, 0); + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.i2cintr = 1; + dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts, + gintsts.d32); + return 1; +} + +/** + * This interrupt indicates that ... + */ +int32_t dwc_otg_pcd_handle_early_suspend_intr(dwc_otg_pcd_t * pcd) +{ + gintsts_data_t gintsts; +#if defined(VERBOSE) + DWC_PRINTF("Early Suspend Detected\n"); +#endif + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.erlysuspend = 1; + dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts, + gintsts.d32); + return 1; +} + +/** + * This function configures EPO to receive SETUP packets. + * + * @todo NGS: Update the comments from the HW FS. + * + * -# Program the following fields in the endpoint specific registers + * for Control OUT EP 0, in order to receive a setup packet + * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back + * setup packets) + * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back + * to back setup packets) + * - In DMA mode, DOEPDMA0 Register with a memory address to + * store any setup packets received + * + * @param core_if Programming view of DWC_otg controller. + * @param pcd Programming view of the PCD. + */ +static inline void ep0_out_start(dwc_otg_core_if_t * core_if, + dwc_otg_pcd_t * pcd) +{ + dwc_otg_dev_if_t *dev_if = core_if->dev_if; + deptsiz0_data_t doeptsize0 = {.d32 = 0 }; + dwc_otg_dev_dma_desc_t *dma_desc; + depctl_data_t doepctl = {.d32 = 0 }; + +#ifdef VERBOSE + DWC_DEBUGPL(DBG_PCDV, "%s() doepctl0=%0x\n", __func__, + dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl)); +#endif + + doeptsize0.b.supcnt = 3; + doeptsize0.b.pktcnt = 1; + doeptsize0.b.xfersize = 8 * 3; + + if (core_if->dma_enable) { + if (!core_if->dma_desc_enable) { + /** put here as for Hermes mode deptisz register should not be written */ + dwc_write_reg32(&dev_if->out_ep_regs[0]->doeptsiz, + doeptsize0.d32); + + /** @todo dma needs to handle multiple setup packets (up to 3) */ + dwc_write_reg32(&dev_if->out_ep_regs[0]->doepdma, + pcd->setup_pkt_dma_handle); + } else { + dev_if->setup_desc_index = + (dev_if->setup_desc_index + 1) & 1; + dma_desc = + dev_if->setup_desc_addr[dev_if->setup_desc_index]; + + /** DMA Descriptor Setup */ + dma_desc->status.b.bs = BS_HOST_BUSY; + dma_desc->status.b.l = 1; + dma_desc->status.b.ioc = 1; + dma_desc->status.b.bytes = pcd->ep0.dwc_ep.maxpacket; + dma_desc->buf = pcd->setup_pkt_dma_handle; + dma_desc->status.b.bs = BS_HOST_READY; + + /** DOEPDMA0 Register write */ + dwc_write_reg32(&dev_if->out_ep_regs[0]->doepdma, + dev_if->dma_setup_desc_addr[dev_if-> + setup_desc_index]); + } + + } else { + /** put here as for Hermes mode deptisz register should not be written */ + dwc_write_reg32(&dev_if->out_ep_regs[0]->doeptsiz, + doeptsize0.d32); + } + + /** DOEPCTL0 Register write */ + doepctl.b.epena = 1; + doepctl.b.cnak = 1; + dwc_write_reg32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32); + +#ifdef VERBOSE + DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n", + dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl)); + DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n", + dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl)); +#endif +} + +/** + * This interrupt occurs when a USB Reset is detected. When the USB + * Reset Interrupt occurs the device state is set to DEFAULT and the + * EP0 state is set to IDLE. + * -# Set the NAK bit for all OUT endpoints (DOEPCTLn.SNAK = 1) + * -# Unmask the following interrupt bits + * - DAINTMSK.INEP0 = 1 (Control 0 IN endpoint) + * - DAINTMSK.OUTEP0 = 1 (Control 0 OUT endpoint) + * - DOEPMSK.SETUP = 1 + * - DOEPMSK.XferCompl = 1 + * - DIEPMSK.XferCompl = 1 + * - DIEPMSK.TimeOut = 1 + * -# Program the following fields in the endpoint specific registers + * for Control OUT EP 0, in order to receive a setup packet + * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back + * setup packets) + * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back + * to back setup packets) + * - In DMA mode, DOEPDMA0 Register with a memory address to + * store any setup packets received + * At this point, all the required initialization, except for enabling + * the control 0 OUT endpoint is done, for receiving SETUP packets. + */ +int32_t dwc_otg_pcd_handle_usb_reset_intr(dwc_otg_pcd_t * pcd) +{ + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); + dwc_otg_dev_if_t *dev_if = core_if->dev_if; + depctl_data_t doepctl = {.d32 = 0 }; + daint_data_t daintmsk = {.d32 = 0 }; + doepmsk_data_t doepmsk = {.d32 = 0 }; + diepmsk_data_t diepmsk = {.d32 = 0 }; + dcfg_data_t dcfg = {.d32 = 0 }; + grstctl_t resetctl = {.d32 = 0 }; + dctl_data_t dctl = {.d32 = 0 }; + int i = 0; + gintsts_data_t gintsts; + pcgcctl_data_t power = {.d32 = 0 }; + + power.d32 = dwc_read_reg32(core_if->pcgcctl); + if (power.b.stoppclk) { + power.d32 = 0; + power.b.stoppclk = 1; + dwc_modify_reg32(core_if->pcgcctl, power.d32, 0); + + power.b.pwrclmp = 1; + dwc_modify_reg32(core_if->pcgcctl, power.d32, 0); + + power.b.rstpdwnmodule = 1; + dwc_modify_reg32(core_if->pcgcctl, power.d32, 0); + } + + core_if->lx_state = DWC_OTG_L0; + + DWC_PRINTF("USB RESET\n"); +#ifdef DWC_EN_ISOC + for (i = 1; i < 16; ++i) { + dwc_otg_pcd_ep_t *ep; + dwc_ep_t *dwc_ep; + ep = get_in_ep(pcd, i); + if (ep != 0) { + dwc_ep = &ep->dwc_ep; + dwc_ep->next_frame = 0xffffffff; + } + } +#endif /* DWC_EN_ISOC */ + + /* reset the HNP settings */ + dwc_otg_pcd_update_otg(pcd, 1); + + /* Clear the Remote Wakeup Signalling */ + dctl.b.rmtwkupsig = 1; + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0); + + /* Set NAK for all OUT EPs */ + doepctl.b.snak = 1; + for (i = 0; i <= dev_if->num_out_eps; i++) { + dwc_write_reg32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32); + } + + /* Flush the NP Tx FIFO */ + dwc_otg_flush_tx_fifo(core_if, 0x10); + /* Flush the Learning Queue */ + resetctl.b.intknqflsh = 1; + dwc_write_reg32(&core_if->core_global_regs->grstctl, resetctl.d32); + + if (core_if->multiproc_int_enable) { + daintmsk.b.inep0 = 1; + daintmsk.b.outep0 = 1; + dwc_write_reg32(&dev_if->dev_global_regs->deachintmsk, + daintmsk.d32); + + doepmsk.b.setup = 1; + doepmsk.b.xfercompl = 1; + doepmsk.b.ahberr = 1; + doepmsk.b.epdisabled = 1; + + if (core_if->dma_desc_enable) { + doepmsk.b.stsphsercvd = 1; + doepmsk.b.bna = 1; + } +/* + doepmsk.b.babble = 1; + doepmsk.b.nyet = 1; + + if(core_if->dma_enable) { + doepmsk.b.nak = 1; + } +*/ + dwc_write_reg32(&dev_if->dev_global_regs->doepeachintmsk[0], + doepmsk.d32); + + diepmsk.b.xfercompl = 1; + diepmsk.b.timeout = 1; + diepmsk.b.epdisabled = 1; + diepmsk.b.ahberr = 1; + diepmsk.b.intknepmis = 1; + + if (core_if->dma_desc_enable) { + diepmsk.b.bna = 1; + } +/* + if(core_if->dma_enable) { + diepmsk.b.nak = 1; + } +*/ + dwc_write_reg32(&dev_if->dev_global_regs->diepeachintmsk[0], + diepmsk.d32); + } else { + daintmsk.b.inep0 = 1; + daintmsk.b.outep0 = 1; + dwc_write_reg32(&dev_if->dev_global_regs->daintmsk, + daintmsk.d32); + + doepmsk.b.setup = 1; + doepmsk.b.xfercompl = 1; + doepmsk.b.ahberr = 1; + doepmsk.b.epdisabled = 1; + + if (core_if->dma_desc_enable) { + doepmsk.b.stsphsercvd = 1; + doepmsk.b.bna = 1; + } + dwc_write_reg32(&dev_if->dev_global_regs->doepmsk, doepmsk.d32); + + diepmsk.b.xfercompl = 1; + diepmsk.b.timeout = 1; + diepmsk.b.epdisabled = 1; + diepmsk.b.ahberr = 1; + diepmsk.b.intknepmis = 1; + + if (core_if->dma_desc_enable) { + diepmsk.b.bna = 1; + } + + dwc_write_reg32(&dev_if->dev_global_regs->diepmsk, diepmsk.d32); + } + + /* Reset Device Address */ + dcfg.d32 = dwc_read_reg32(&dev_if->dev_global_regs->dcfg); + dcfg.b.devaddr = 0; + dwc_write_reg32(&dev_if->dev_global_regs->dcfg, dcfg.d32); + + /* setup EP0 to receive SETUP packets */ + ep0_out_start(core_if, pcd); + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.usbreset = 1; + dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32); + + return 1; +} + +/** + * Get the device speed from the device status register and convert it + * to USB speed constant. + * + * @param core_if Programming view of DWC_otg controller. + */ +static int get_device_speed(dwc_otg_core_if_t * core_if) +{ + dsts_data_t dsts; + int speed = 0; + dsts.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts); + + switch (dsts.b.enumspd) { + case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: + speed = USB_SPEED_HIGH; + break; + case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: + case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ: + speed = USB_SPEED_FULL; + break; + + case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ: + speed = USB_SPEED_LOW; + break; + } + + return speed; +} + +/** + * Read the device status register and set the device speed in the + * data structure. + * Set up EP0 to receive SETUP packets by calling dwc_ep0_activate. + */ +int32_t dwc_otg_pcd_handle_enum_done_intr(dwc_otg_pcd_t * pcd) +{ + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0; + gintsts_data_t gintsts; + gusbcfg_data_t gusbcfg; + dwc_otg_core_global_regs_t *global_regs = + GET_CORE_IF(pcd)->core_global_regs; + uint8_t utmi16b, utmi8b; + int speed; + DWC_DEBUGPL(DBG_PCD, "SPEED ENUM\n"); + + if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_2_60a) { + utmi16b = 6; + utmi8b = 9; + } else { + utmi16b = 4; + utmi8b = 8; + } + dwc_otg_ep0_activate(GET_CORE_IF(pcd), &ep0->dwc_ep); + +#ifdef DEBUG_EP0 + print_ep0_state(pcd); +#endif + + if (pcd->ep0state == EP0_DISCONNECT) { + pcd->ep0state = EP0_IDLE; + } else if (pcd->ep0state == EP0_STALL) { + pcd->ep0state = EP0_IDLE; + } + + pcd->ep0state = EP0_IDLE; + + ep0->stopped = 0; + + speed = get_device_speed(GET_CORE_IF(pcd)); + pcd->fops->connect(pcd, speed); + + /* Set USB turnaround time based on device speed and PHY interface. */ + gusbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); + if (speed == USB_SPEED_HIGH) { + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type == + DWC_HWCFG2_HS_PHY_TYPE_ULPI) { + /* ULPI interface */ + gusbcfg.b.usbtrdtim = 9; + } + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type == + DWC_HWCFG2_HS_PHY_TYPE_UTMI) { + /* UTMI+ interface */ + if (GET_CORE_IF(pcd)->hwcfg4.b.utmi_phy_data_width == 0) { + gusbcfg.b.usbtrdtim = utmi8b; + } else if (GET_CORE_IF(pcd)->hwcfg4.b. + utmi_phy_data_width == 1) { + gusbcfg.b.usbtrdtim = utmi16b; + } else if (GET_CORE_IF(pcd)->core_params-> + phy_utmi_width == 8) { + gusbcfg.b.usbtrdtim = utmi8b; + } else { + gusbcfg.b.usbtrdtim = utmi16b; + } + } + if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type == + DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI) { + /* UTMI+ OR ULPI interface */ + if (gusbcfg.b.ulpi_utmi_sel == 1) { + /* ULPI interface */ + gusbcfg.b.usbtrdtim = 9; + } else { + /* UTMI+ interface */ + if (GET_CORE_IF(pcd)->core_params-> + phy_utmi_width == 16) { + gusbcfg.b.usbtrdtim = utmi16b; + } else { + gusbcfg.b.usbtrdtim = utmi8b; + } + } + } + } else { + /* Full or low speed */ + gusbcfg.b.usbtrdtim = 9; + } + dwc_write_reg32(&global_regs->gusbcfg, gusbcfg.d32); + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.enumdone = 1; + dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts, + gintsts.d32); + return 1; +} + +/** + * This interrupt indicates that the ISO OUT Packet was dropped due to + * Rx FIFO full or Rx Status Queue Full. If this interrupt occurs + * read all the data from the Rx FIFO. + */ +int32_t dwc_otg_pcd_handle_isoc_out_packet_dropped_intr(dwc_otg_pcd_t * pcd) +{ + gintmsk_data_t intr_mask = {.d32 = 0 }; + gintsts_data_t gintsts; + + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", + "ISOC Out Dropped"); + + intr_mask.b.isooutdrop = 1; + dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk, + intr_mask.d32, 0); + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.isooutdrop = 1; + dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts, + gintsts.d32); + + return 1; +} + +/** + * This interrupt indicates the end of the portion of the micro-frame + * for periodic transactions. If there is a periodic transaction for + * the next frame, load the packets into the EP periodic Tx FIFO. + */ +int32_t dwc_otg_pcd_handle_end_periodic_frame_intr(dwc_otg_pcd_t * pcd) +{ + gintmsk_data_t intr_mask = {.d32 = 0 }; + gintsts_data_t gintsts; + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "EOP"); + + intr_mask.b.eopframe = 1; + dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk, + intr_mask.d32, 0); + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.eopframe = 1; + dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts, + gintsts.d32); + + return 1; +} + +/** + * This interrupt indicates that EP of the packet on the top of the + * non-periodic Tx FIFO does not match EP of the IN Token received. + * + * The "Device IN Token Queue" Registers are read to determine the + * order the IN Tokens have been received. The non-periodic Tx FIFO + * is flushed, so it can be reloaded in the order seen in the IN Token + * Queue. + */ +int32_t dwc_otg_pcd_handle_ep_mismatch_intr(dwc_otg_core_if_t * core_if) +{ + gintsts_data_t gintsts; + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if); + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.epmismatch = 1; + dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32); + + return 1; +} + +/** + * This funcion stalls EP0. + */ +static inline void ep0_do_stall(dwc_otg_pcd_t * pcd, const int err_val) +{ + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0; + usb_device_request_t *ctrl = &pcd->setup_pkt->req; + DWC_WARN("req %02x.%02x protocol STALL; err %d\n", + ctrl->bmRequestType, ctrl->bRequest, err_val); + + ep0->dwc_ep.is_in = 1; + dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep0->dwc_ep); + pcd->ep0.stopped = 1; + pcd->ep0state = EP0_IDLE; + ep0_out_start(GET_CORE_IF(pcd), pcd); +} + +/** + * This functions delegates the setup command to the gadget driver. + */ +static inline void do_gadget_setup(dwc_otg_pcd_t * pcd, + usb_device_request_t * ctrl) +{ + int ret = 0; + DWC_SPINUNLOCK(pcd->lock); + ret = pcd->fops->setup(pcd, (uint8_t *) ctrl); + DWC_SPINLOCK(pcd->lock); + if (ret < 0) { + ep0_do_stall(pcd, ret); + } + + /** @todo This is a g_file_storage gadget driver specific + * workaround: a DELAYED_STATUS result from the fsg_setup + * routine will result in the gadget queueing a EP0 IN status + * phase for a two-stage control transfer. Exactly the same as + * a SET_CONFIGURATION/SET_INTERFACE except that this is a class + * specific request. Need a generic way to know when the gadget + * driver will queue the status phase. Can we assume when we + * call the gadget driver setup() function that it will always + * queue and require the following flag? Need to look into + * this. + */ + + if (ret == 256 + 999) { + pcd->request_config = 1; + } +} + +#ifdef DWC_UTE_CFI +/** + * This functions delegates the CFI setup commands to the gadget driver. + * This function will return a negative value to indicate a failure. + */ +static inline int cfi_gadget_setup(dwc_otg_pcd_t * pcd, + struct cfi_usb_ctrlrequest *ctrl_req) +{ + int ret = 0; + + if (pcd->fops && pcd->fops->cfi_setup) { + DWC_SPINUNLOCK(pcd->lock); + ret = pcd->fops->cfi_setup(pcd, ctrl_req); + DWC_SPINLOCK(pcd->lock); + if (ret < 0) { + ep0_do_stall(pcd, ret); + return ret; + } + } + + return ret; +} +#endif + +/** + * This function starts the Zero-Length Packet for the IN status phase + * of a 2 stage control transfer. + */ +static inline void do_setup_in_status_phase(dwc_otg_pcd_t * pcd) +{ + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0; + if (pcd->ep0state == EP0_STALL) { + return; + } + + pcd->ep0state = EP0_IN_STATUS_PHASE; + + /* Prepare for more SETUP Packets */ + DWC_DEBUGPL(DBG_PCD, "EP0 IN ZLP\n"); + ep0->dwc_ep.xfer_len = 0; + ep0->dwc_ep.xfer_count = 0; + ep0->dwc_ep.is_in = 1; + ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle; + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep); + + /* Prepare for more SETUP Packets */ + //ep0_out_start(GET_CORE_IF(pcd), pcd); +} + +/** + * This function starts the Zero-Length Packet for the OUT status phase + * of a 2 stage control transfer. + */ +static inline void do_setup_out_status_phase(dwc_otg_pcd_t * pcd) +{ + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0; + if (pcd->ep0state == EP0_STALL) { + DWC_DEBUGPL(DBG_PCD, "EP0 STALLED\n"); + return; + } + pcd->ep0state = EP0_OUT_STATUS_PHASE; + + DWC_DEBUGPL(DBG_PCD, "EP0 OUT ZLP\n"); + ep0->dwc_ep.xfer_len = 0; + ep0->dwc_ep.xfer_count = 0; + ep0->dwc_ep.is_in = 0; + ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle; + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep); + + /* Prepare for more SETUP Packets */ + if (GET_CORE_IF(pcd)->dma_enable == 0) { + ep0_out_start(GET_CORE_IF(pcd), pcd); + } +} + +/** + * Clear the EP halt (STALL) and if pending requests start the + * transfer. + */ +static inline void pcd_clear_halt(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep) +{ + if (ep->dwc_ep.stall_clear_flag == 0) + dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep); + + /* Reactive the EP */ + dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep); + if (ep->stopped) { + ep->stopped = 0; + /* If there is a request in the EP queue start it */ + + /** @todo FIXME: this causes an EP mismatch in DMA mode. + * epmismatch not yet implemented. */ + + /* + * Above fixme is solved by implmenting a tasklet to call the + * start_next_request(), outside of interrupt context at some + * time after the current time, after a clear-halt setup packet. + * Still need to implement ep mismatch in the future if a gadget + * ever uses more than one endpoint at once + */ + ep->queue_sof = 1; + DWC_TASK_SCHEDULE(pcd->start_xfer_tasklet); + } + /* Start Control Status Phase */ + do_setup_in_status_phase(pcd); +} + +/** + * This function is called when the SET_FEATURE TEST_MODE Setup packet + * is sent from the host. The Device Control register is written with + * the Test Mode bits set to the specified Test Mode. This is done as + * a tasklet so that the "Status" phase of the control transfer + * completes before transmitting the TEST packets. + * + * @todo This has not been tested since the tasklet struct was put + * into the PCD struct! + * + */ +void do_test_mode(void *data) +{ + dctl_data_t dctl; + dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data; + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); + int test_mode = pcd->test_mode; + +// DWC_WARN("%s() has not been tested since being rewritten!\n", __func__); + + dctl.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dctl); + switch (test_mode) { + case 1: // TEST_J + dctl.b.tstctl = 1; + break; + + case 2: // TEST_K + dctl.b.tstctl = 2; + break; + + case 3: // TEST_SE0_NAK + dctl.b.tstctl = 3; + break; + + case 4: // TEST_PACKET + dctl.b.tstctl = 4; + break; + + case 5: // TEST_FORCE_ENABLE + dctl.b.tstctl = 5; + break; + } + dwc_write_reg32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32); +} + +/** + * This function process the GET_STATUS Setup Commands. + */ +static inline void do_get_status(dwc_otg_pcd_t * pcd) +{ + usb_device_request_t ctrl = pcd->setup_pkt->req; + dwc_otg_pcd_ep_t *ep; + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0; + uint16_t *status = pcd->status_buf; + +#ifdef DEBUG_EP0 + DWC_DEBUGPL(DBG_PCD, + "GET_STATUS %02x.%02x v%04x i%04x l%04x\n", + ctrl.bmRequestType, ctrl.bRequest, + UGETW(ctrl.wValue), UGETW(ctrl.wIndex), + UGETW(ctrl.wLength)); +#endif + + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) { + case UT_DEVICE: + *status = 0x1; /* Self powered */ + *status |= pcd->remote_wakeup_enable << 1; + break; + + case UT_INTERFACE: + *status = 0; + break; + + case UT_ENDPOINT: + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex)); + if (ep == 0 || UGETW(ctrl.wLength) > 2) { + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED); + return; + } + /** @todo check for EP stall */ + *status = ep->stopped; + break; + } + pcd->ep0_pending = 1; + ep0->dwc_ep.start_xfer_buff = (uint8_t *) status; + ep0->dwc_ep.xfer_buff = (uint8_t *) status; + ep0->dwc_ep.dma_addr = pcd->status_buf_dma_handle; + ep0->dwc_ep.xfer_len = 2; + ep0->dwc_ep.xfer_count = 0; + ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len; + dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep); +} + +/** + * This function process the SET_FEATURE Setup Commands. + */ +static inline void do_set_feature(dwc_otg_pcd_t * pcd) +{ + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; + usb_device_request_t ctrl = pcd->setup_pkt->req; + dwc_otg_pcd_ep_t *ep = 0; + int32_t otg_cap_param = core_if->core_params->otg_cap; + gotgctl_data_t gotgctl = {.d32 = 0 }; + + DWC_DEBUGPL(DBG_PCD, "SET_FEATURE:%02x.%02x v%04x i%04x l%04x\n", + ctrl.bmRequestType, ctrl.bRequest, + UGETW(ctrl.wValue), UGETW(ctrl.wIndex), + UGETW(ctrl.wLength)); + DWC_DEBUGPL(DBG_PCD, "otg_cap=%d\n", otg_cap_param); + + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) { + case UT_DEVICE: + switch (UGETW(ctrl.wValue)) { + case UF_DEVICE_REMOTE_WAKEUP: + pcd->remote_wakeup_enable = 1; + break; + + case UF_TEST_MODE: + /* Setup the Test Mode tasklet to do the Test + * Packet generation after the SETUP Status + * phase has completed. */ + + /** @todo This has not been tested since the + * tasklet struct was put into the PCD + * struct! */ + pcd->test_mode = UGETW(ctrl.wIndex) >> 8; + DWC_TASK_SCHEDULE(pcd->test_mode_tasklet); + break; + + case UF_DEVICE_B_HNP_ENABLE: + DWC_DEBUGPL(DBG_PCDV, + "SET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n"); + + /* dev may initiate HNP */ + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) { + pcd->b_hnp_enable = 1; + dwc_otg_pcd_update_otg(pcd, 0); + DWC_DEBUGPL(DBG_PCD, "Request B HNP\n"); + /**@todo Is the gotgctl.devhnpen cleared + * by a USB Reset? */ + gotgctl.b.devhnpen = 1; + gotgctl.b.hnpreq = 1; + dwc_write_reg32(&global_regs->gotgctl, + gotgctl.d32); + } else { + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED); + } + break; + + case UF_DEVICE_A_HNP_SUPPORT: + /* RH port supports HNP */ + DWC_DEBUGPL(DBG_PCDV, + "SET_FEATURE: USB_DEVICE_A_HNP_SUPPORT\n"); + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) { + pcd->a_hnp_support = 1; + dwc_otg_pcd_update_otg(pcd, 0); + } else { + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED); + } + break; + + case UF_DEVICE_A_ALT_HNP_SUPPORT: + /* other RH port does */ + DWC_DEBUGPL(DBG_PCDV, + "SET_FEATURE: USB_DEVICE_A_ALT_HNP_SUPPORT\n"); + if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) { + pcd->a_alt_hnp_support = 1; + dwc_otg_pcd_update_otg(pcd, 0); + } else { + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED); + } + break; + } + do_setup_in_status_phase(pcd); + break; + + case UT_INTERFACE: + do_gadget_setup(pcd, &ctrl); + break; + + case UT_ENDPOINT: + if (UGETW(ctrl.wValue) == UF_ENDPOINT_HALT) { + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex)); + if (ep == 0) { + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED); + return; + } + ep->stopped = 1; + dwc_otg_ep_set_stall(core_if, &ep->dwc_ep); + } + do_setup_in_status_phase(pcd); + break; + } +} + +/** + * This function process the CLEAR_FEATURE Setup Commands. + */ +static inline void do_clear_feature(dwc_otg_pcd_t * pcd) +{ + usb_device_request_t ctrl = pcd->setup_pkt->req; + dwc_otg_pcd_ep_t *ep = 0; + + DWC_DEBUGPL(DBG_PCD, + "CLEAR_FEATURE:%02x.%02x v%04x i%04x l%04x\n", + ctrl.bmRequestType, ctrl.bRequest, + UGETW(ctrl.wValue), UGETW(ctrl.wIndex), + UGETW(ctrl.wLength)); + + switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) { + case UT_DEVICE: + switch (UGETW(ctrl.wValue)) { + case UF_DEVICE_REMOTE_WAKEUP: + pcd->remote_wakeup_enable = 0; + break; + + case UF_TEST_MODE: + /** @todo Add CLEAR_FEATURE for TEST modes. */ + break; + } + do_setup_in_status_phase(pcd); + break; + + case UT_ENDPOINT: + ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex)); + if (ep == 0) { + ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED); + return; + } + + pcd_clear_halt(pcd, ep); + + break; + } +} + +/** + * This function process the SET_ADDRESS Setup Commands. + */ +static inline void do_set_address(dwc_otg_pcd_t * pcd) +{ + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if; + usb_device_request_t ctrl = pcd->setup_pkt->req; + + if (ctrl.bmRequestType == UT_DEVICE) { + dcfg_data_t dcfg = {.d32 = 0 }; + +#ifdef DEBUG_EP0 +// DWC_DEBUGPL(DBG_PCDV, "SET_ADDRESS:%d\n", ctrl.wValue); +#endif + dcfg.b.devaddr = UGETW(ctrl.wValue); + dwc_modify_reg32(&dev_if->dev_global_regs->dcfg, 0, dcfg.d32); + do_setup_in_status_phase(pcd); + } +} + +/** + * This function processes SETUP commands. In Linux, the USB Command + * processing is done in two places - the first being the PCD and the + * second in the Gadget Driver (for example, the File-Backed Storage + * Gadget Driver). + * + *
Parameter NameMeaning
otg_capSpecifies the OTG capabilities. The driver will automatically detect the + value for this parameter if none is specified. + - 0: HNP and SRP capable (default, if available) + - 1: SRP Only capable + - 2: No HNP/SRP capable +
dma_enableSpecifies whether to use slave or DMA mode for accessing the data FIFOs. + The driver will automatically detect the value for this parameter if none is + specified. + - 0: Slave + - 1: DMA (default, if available) +
dma_burst_sizeThe DMA Burst size (applicable only for External DMA Mode). + - Values: 1, 4, 8 16, 32, 64, 128, 256 (default 32) +
speedSpecifies the maximum speed of operation in host and device mode. The + actual speed depends on the speed of the attached device and the value of + phy_type. + - 0: High Speed (default) + - 1: Full Speed +
host_support_fs_ls_low_powerSpecifies whether low power mode is supported when attached to a Full + Speed or Low Speed device in host mode. + - 0: Don't support low power mode (default) + - 1: Support low power mode +
host_ls_low_power_phy_clkSpecifies the PHY clock rate in low power mode when connected to a Low + Speed device in host mode. This parameter is applicable only if + HOST_SUPPORT_FS_LS_LOW_POWER is enabled. + - 0: 48 MHz (default) + - 1: 6 MHz +
enable_dynamic_fifo Specifies whether FIFOs may be resized by the driver software. + - 0: Use cC FIFO size parameters + - 1: Allow dynamic FIFO sizing (default) +
data_fifo_sizeTotal number of 4-byte words in the data FIFO memory. This memory + includes the Rx FIFO, non-periodic Tx FIFO, and periodic Tx FIFOs. + - Values: 32 to 32768 (default 8192) + + Note: The total FIFO memory depth in the FPGA configuration is 8192. +
dev_rx_fifo_sizeNumber of 4-byte words in the Rx FIFO in device mode when dynamic + FIFO sizing is enabled. + - Values: 16 to 32768 (default 1064) +
dev_nperio_tx_fifo_sizeNumber of 4-byte words in the non-periodic Tx FIFO in device mode when + dynamic FIFO sizing is enabled. + - Values: 16 to 32768 (default 1024) +
dev_perio_tx_fifo_size_n (n = 1 to 15)Number of 4-byte words in each of the periodic Tx FIFOs in device mode + when dynamic FIFO sizing is enabled. + - Values: 4 to 768 (default 256) +
host_rx_fifo_sizeNumber of 4-byte words in the Rx FIFO in host mode when dynamic FIFO + sizing is enabled. + - Values: 16 to 32768 (default 1024) +
host_nperio_tx_fifo_sizeNumber of 4-byte words in the non-periodic Tx FIFO in host mode when + dynamic FIFO sizing is enabled in the core. + - Values: 16 to 32768 (default 1024) +
host_perio_tx_fifo_sizeNumber of 4-byte words in the host periodic Tx FIFO when dynamic FIFO + sizing is enabled. + - Values: 16 to 32768 (default 1024) +
max_transfer_sizeThe maximum transfer size supported in bytes. + - Values: 2047 to 65,535 (default 65,535) +
max_packet_countThe maximum number of packets in a transfer. + - Values: 15 to 511 (default 511) +
host_channelsThe number of host channel registers to use. + - Values: 1 to 16 (default 12) + + Note: The FPGA configuration supports a maximum of 12 host channels. +
dev_endpointsThe number of endpoints in addition to EP0 available for device mode + operations. + - Values: 1 to 15 (default 6 IN and OUT) + + Note: The FPGA configuration supports a maximum of 6 IN and OUT endpoints in + addition to EP0. +
phy_typeSpecifies the type of PHY interface to use. By default, the driver will + automatically detect the phy_type. + - 0: Full Speed + - 1: UTMI+ (default, if available) + - 2: ULPI +
phy_utmi_widthSpecifies the UTMI+ Data Width. This parameter is applicable for a + phy_type of UTMI+. Also, this parameter is applicable only if the + OTG_HSPHY_WIDTH cC parameter was set to "8 and 16 bits", meaning that the + core has been configured to work at either data path width. + - Values: 8 or 16 bits (default 16) +
phy_ulpi_ddrSpecifies whether the ULPI operates at double or single data rate. This + parameter is only applicable if phy_type is ULPI. + - 0: single data rate ULPI interface with 8 bit wide data bus (default) + - 1: double data rate ULPI interface with 4 bit wide data bus +
i2c_enableSpecifies whether to use the I2C interface for full speed PHY. This + parameter is only applicable if PHY_TYPE is FS. + - 0: Disabled (default) + - 1: Enabled +
otg_en_multiple_tx_fifoSpecifies whether dedicatedto tx fifos are enabled for non periodic IN EPs. + The driver will automatically detect the value for this parameter if none is + specified. + - 0: Disabled + - 1: Enabled (default, if available) +
dev_tx_fifo_size_n (n = 1 to 15)Number of 4-byte words in each of the Tx FIFOs in device mode + when dynamic FIFO sizing is enabled. + - Values: 4 to 768 (default 256) +
tx_thr_lengthTransmit Threshold length in 32 bit double words + - Values: 8 to 128 (default 64) +
rx_thr_lengthReceive Threshold length in 32 bit double words + - Values: 8 to 128 (default 64) +
thr_ctlSpecifies whether to enable Thresholding for Device mode. Bits 0, 1, 2 of this + parmater specifies if thresholding is enabled for non-Iso Tx, Iso Tx and Rx + transfers accordingly. + The driver will automatically detect the value for this parameter if none is + specified. + - Values: 0 to 7 (default 0) + Bit values indicate: + - 0: Thresholding disabled + - 1: Thresholding enabled +
dma_desc_enableSpecifies whether to enable Descriptor DMA mode. + The driver will automatically detect the value for this parameter if none is + specified. + - 0: Descriptor DMA disabled + - 1: Descriptor DMA (default, if available) +
mpi_enableSpecifies whether to enable MPI enhancement mode. + The driver will automatically detect the value for this parameter if none is + specified. + - 0: MPI disabled (default) + - 1: MPI enable +
pti_enableSpecifies whether to enable PTI enhancement support. + The driver will automatically detect the value for this parameter if none is + specified. + - 0: PTI disabled (default) + - 1: PTI enable +
lpm_enableSpecifies whether to enable LPM support. + The driver will automatically detect the value for this parameter if none is + specified. + - 0: LPM disabled + - 1: LPM enable (default, if available) +
ahb_thr_ratioSpecifies AHB Threshold ratio. + - Values: 0 to 3 (default 0) +
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Command Driver Description
GET_STATUS PCD Command is processed as + * defined in chapter 9 of the USB 2.0 Specification chapter 9 + *
CLEAR_FEATURE PCD The Device and Endpoint + * requests are the ENDPOINT_HALT feature is procesed, all others the + * interface requests are ignored.
SET_FEATURE PCD The Device and Endpoint + * requests are processed by the PCD. Interface requests are passed + * to the Gadget Driver.
SET_ADDRESS PCD Program the DCFG reg, + * with device address received
GET_DESCRIPTOR Gadget Driver Return the + * requested descriptor
SET_DESCRIPTOR Gadget Driver Optional - + * not implemented by any of the existing Gadget Drivers.
SET_CONFIGURATION Gadget Driver Disable + * all EPs and enable EPs for new configuration.
GET_CONFIGURATION Gadget Driver Return + * the current configuration
SET_INTERFACE Gadget Driver Disable all + * EPs and enable EPs for new configuration.
GET_INTERFACE Gadget Driver Return the + * current interface.
SYNC_FRAME PCD Display debug + * message.
+ * + * When the SETUP Phase Done interrupt occurs, the PCD SETUP commands are + * processed by pcd_setup. Calling the Function Driver's setup function from + * pcd_setup processes the gadget SETUP commands. + */ +static inline void pcd_setup(dwc_otg_pcd_t * pcd) +{ + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); + dwc_otg_dev_if_t *dev_if = core_if->dev_if; + usb_device_request_t ctrl = pcd->setup_pkt->req; + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0; + + deptsiz0_data_t doeptsize0 = {.d32 = 0 }; + +#ifdef DWC_UTE_CFI + int retval = 0; + struct cfi_usb_ctrlrequest cfi_req; +#endif + +#ifdef DEBUG_EP0 + DWC_DEBUGPL(DBG_PCD, "SETUP %02x.%02x v%04x i%04x l%04x\n", + ctrl.bmRequestType, ctrl.bRequest, + UGETW(ctrl.wValue), UGETW(ctrl.wIndex), + UGETW(ctrl.wLength)); +#endif + + doeptsize0.d32 = dwc_read_reg32(&dev_if->out_ep_regs[0]->doeptsiz); + + /** @todo handle > 1 setup packet , assert error for now */ + + if (core_if->dma_enable && core_if->dma_desc_enable == 0 + && (doeptsize0.b.supcnt < 2)) { + DWC_ERROR + ("\n\n----------- CANNOT handle > 1 setup packet in DMA mode\n\n"); + } + + /* Clean up the request queue */ + dwc_otg_request_nuke(ep0); + ep0->stopped = 0; + + if (ctrl.bmRequestType & UE_DIR_IN) { + ep0->dwc_ep.is_in = 1; + pcd->ep0state = EP0_IN_DATA_PHASE; + } else { + ep0->dwc_ep.is_in = 0; + pcd->ep0state = EP0_OUT_DATA_PHASE; + } + + if (UGETW(ctrl.wLength) == 0) { + ep0->dwc_ep.is_in = 1; + pcd->ep0state = EP0_IN_STATUS_PHASE; + } + + if (UT_GET_TYPE(ctrl.bmRequestType) != UT_STANDARD) { + +#ifdef DWC_UTE_CFI + DWC_MEMCPY(&cfi_req, &ctrl, sizeof(usb_device_request_t)); + + //printk(KERN_ALERT "CFI: req_type=0x%02x; req=0x%02x\n", ctrl.bRequestType, ctrl.bRequest); + if (UT_GET_TYPE(cfi_req.bRequestType) == UT_VENDOR) { + if (cfi_req.bRequest > 0xB0 && cfi_req.bRequest < 0xBF) { + retval = cfi_setup(pcd, &cfi_req); + if (retval < 0) { + ep0_do_stall(pcd, retval); + pcd->ep0_pending = 0; + return; + } + + /* if need gadget setup then call it and check the retval */ + if (pcd->cfi->need_gadget_att) { + retval = + cfi_gadget_setup(pcd, + &pcd->cfi-> + ctrl_req); + if (retval < 0) { + pcd->ep0_pending = 0; + return; + } + } + + if (pcd->cfi->need_status_in_complete) { + do_setup_in_status_phase(pcd); + } + return; + } + } +#endif + + /* handle non-standard (class/vendor) requests in the gadget driver */ + do_gadget_setup(pcd, &ctrl); + return; + } + + /** @todo NGS: Handle bad setup packet? */ + +/////////////////////////////////////////// +//// --- Standard Request handling --- //// + + switch (ctrl.bRequest) { + case UR_GET_STATUS: + do_get_status(pcd); + break; + + case UR_CLEAR_FEATURE: + do_clear_feature(pcd); + break; + + case UR_SET_FEATURE: + do_set_feature(pcd); + break; + + case UR_SET_ADDRESS: + do_set_address(pcd); + break; + + case UR_SET_INTERFACE: + case UR_SET_CONFIG: +// _pcd->request_config = 1; /* Configuration changed */ + do_gadget_setup(pcd, &ctrl); + break; + + case UR_SYNCH_FRAME: + do_gadget_setup(pcd, &ctrl); + break; + + default: + /* Call the Gadget Driver's setup functions */ + do_gadget_setup(pcd, &ctrl); + break; + } +} + +/** + * This function completes the ep0 control transfer. + */ +static int32_t ep0_complete_request(dwc_otg_pcd_ep_t * ep) +{ + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd); + dwc_otg_dev_if_t *dev_if = core_if->dev_if; + dwc_otg_dev_in_ep_regs_t *in_ep_regs = + dev_if->in_ep_regs[ep->dwc_ep.num]; +#ifdef DEBUG_EP0 + dwc_otg_dev_out_ep_regs_t *out_ep_regs = + dev_if->out_ep_regs[ep->dwc_ep.num]; +#endif + deptsiz0_data_t deptsiz; + dev_dma_desc_sts_t desc_sts; + dwc_otg_pcd_request_t *req; + int is_last = 0; + dwc_otg_pcd_t *pcd = ep->pcd; + +#ifdef DWC_UTE_CFI + struct cfi_usb_ctrlrequest *ctrlreq; + int retval = -DWC_E_NOT_SUPPORTED; +#endif + + if (pcd->ep0_pending && DWC_CIRCLEQ_EMPTY(&ep->queue)) { + if (ep->dwc_ep.is_in) { +#ifdef DEBUG_EP0 + DWC_DEBUGPL(DBG_PCDV, "Do setup OUT status phase\n"); +#endif + do_setup_out_status_phase(pcd); + } else { +#ifdef DEBUG_EP0 + DWC_DEBUGPL(DBG_PCDV, "Do setup IN status phase\n"); +#endif + +#ifdef DWC_UTE_CFI + ctrlreq = &pcd->cfi->ctrl_req; + + if (UT_GET_TYPE(ctrlreq->bRequestType) == UT_VENDOR) { + if (ctrlreq->bRequest > 0xB0 + && ctrlreq->bRequest < 0xBF) { + + /* Return if the PCD failed to handle the request */ + if ((retval = + pcd->cfi->ops. + ctrl_write_complete(pcd->cfi, + pcd)) < 0) { + CFI_INFO + ("ERROR setting a new value in the PCD(%d)\n", + retval); + ep0_do_stall(pcd, retval); + pcd->ep0_pending = 0; + return 0; + } + + /* If the gadget needs to be notified on the request */ + if (pcd->cfi->need_gadget_att == 1) { + //retval = do_gadget_setup(pcd, &pcd->cfi->ctrl_req); + retval = + cfi_gadget_setup(pcd, + &pcd->cfi-> + ctrl_req); + + /* Return from the function if the gadget failed to process + * the request properly - this should never happen !!! + */ + if (retval < 0) { + CFI_INFO + ("ERROR setting a new value in the gadget(%d)\n", + retval); + pcd->ep0_pending = 0; + return 0; + } + } + + CFI_INFO("%s: RETVAL=%d\n", __func__, + retval); + /* If we hit here then the PCD and the gadget has properly + * handled the request - so send the ZLP IN to the host. + */ + /* @todo: MAS - decide whether we need to start the setup + * stage based on the need_setup value of the cfi object + */ + do_setup_in_status_phase(pcd); + pcd->ep0_pending = 0; + return 1; + } + } +#endif + + do_setup_in_status_phase(pcd); + } + pcd->ep0_pending = 0; + return 1; + } + + if (DWC_CIRCLEQ_EMPTY(&ep->queue)) { + return 0; + } + req = DWC_CIRCLEQ_FIRST(&ep->queue); + + if (pcd->ep0state == EP0_OUT_STATUS_PHASE + || pcd->ep0state == EP0_IN_STATUS_PHASE) { + is_last = 1; + } else if (ep->dwc_ep.is_in) { + deptsiz.d32 = dwc_read_reg32(&in_ep_regs->dieptsiz); + if (core_if->dma_desc_enable != 0) + desc_sts = dev_if->in_desc_addr->status; +#ifdef DEBUG_EP0 + DWC_DEBUGPL(DBG_PCDV, "%d len=%d xfersize=%d pktcnt=%d\n", + ep->dwc_ep.num, ep->dwc_ep.xfer_len, + deptsiz.b.xfersize, deptsiz.b.pktcnt); +#endif + + if (((core_if->dma_desc_enable == 0) + && (deptsiz.b.xfersize == 0)) + || ((core_if->dma_desc_enable != 0) + && (desc_sts.b.bytes == 0))) { + req->actual = ep->dwc_ep.xfer_count; + /* Is a Zero Len Packet needed? */ + if (req->sent_zlp) { +#ifdef DEBUG_EP0 + DWC_DEBUGPL(DBG_PCD, "Setup Rx ZLP\n"); +#endif + req->sent_zlp = 0; + } + do_setup_out_status_phase(pcd); + } + } else { + /* ep0-OUT */ +#ifdef DEBUG_EP0 + deptsiz.d32 = dwc_read_reg32(&out_ep_regs->doeptsiz); + DWC_DEBUGPL(DBG_PCDV, "%d len=%d xsize=%d pktcnt=%d\n", + ep->dwc_ep.num, ep->dwc_ep.xfer_len, + deptsiz.b.xfersize, deptsiz.b.pktcnt); +#endif + req->actual = ep->dwc_ep.xfer_count; + + /* Is a Zero Len Packet needed? */ + if (req->sent_zlp) { +#ifdef DEBUG_EP0 + DWC_DEBUGPL(DBG_PCDV, "Setup Tx ZLP\n"); +#endif + req->sent_zlp = 0; + } + if (core_if->dma_desc_enable == 0) + do_setup_in_status_phase(pcd); + } + + /* Complete the request */ + if (is_last) { + dwc_otg_request_done(ep, req, 0); + ep->dwc_ep.start_xfer_buff = 0; + ep->dwc_ep.xfer_buff = 0; + ep->dwc_ep.xfer_len = 0; + return 1; + } + return 0; +} + +#ifdef DWC_UTE_CFI +/** + * This function calculates traverses all the CFI DMA descriptors and + * and accumulates the bytes that are left to be transfered. + * + * @return The total bytes left to transfered, or a negative value as failure + */ +static inline int cfi_calc_desc_residue(dwc_otg_pcd_ep_t * ep) +{ + int32_t ret = 0; + int i; + struct dwc_otg_dma_desc *ddesc = NULL; + struct cfi_ep *cfiep; + + /* See if the pcd_ep has its respective cfi_ep mapped */ + cfiep = get_cfi_ep_by_pcd_ep(ep->pcd->cfi, ep); + if (!cfiep) { + CFI_INFO("%s: Failed to find ep\n", __func__); + return -1; + } + + ddesc = ep->dwc_ep.descs; + + for (i = 0; (i < cfiep->desc_count) && (i < MAX_DMA_DESCS_PER_EP); i++) { + +#if defined(PRINT_CFI_DMA_DESCS) + print_desc(ddesc, ep->ep.name, i); +#endif + ret += ddesc->status.b.bytes; + ddesc++; + } + + if (ret) + CFI_INFO("!!!!!!!!!! WARNING (%s) - residue=%d\n", __func__, + ret); + + return ret; +} +#endif + +/** + * This function completes the request for the EP. If there are + * additional requests for the EP in the queue they will be started. + */ +static void complete_ep(dwc_otg_pcd_ep_t * ep) +{ + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd); + dwc_otg_dev_if_t *dev_if = core_if->dev_if; + dwc_otg_dev_in_ep_regs_t *in_ep_regs = + dev_if->in_ep_regs[ep->dwc_ep.num]; + deptsiz_data_t deptsiz; + dev_dma_desc_sts_t desc_sts; + dwc_otg_pcd_request_t *req = 0; + dwc_otg_dev_dma_desc_t *dma_desc; + uint32_t byte_count = 0; + int is_last = 0; + int i; + + DWC_DEBUGPL(DBG_PCDV, "%s() %d-%s\n", __func__, ep->dwc_ep.num, + (ep->dwc_ep.is_in ? "IN" : "OUT")); + + /* Get any pending requests */ + if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) { + req = DWC_CIRCLEQ_FIRST(&ep->queue); + if (!req) { + DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep); + return; + } + } else { + DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep); + return; + } + + DWC_DEBUGPL(DBG_PCD, "Requests %d\n", ep->pcd->request_pending); + + if (ep->dwc_ep.is_in) { + deptsiz.d32 = dwc_read_reg32(&in_ep_regs->dieptsiz); + + if (core_if->dma_enable) { + if (core_if->dma_desc_enable == 0) { + if (deptsiz.b.xfersize == 0 + && deptsiz.b.pktcnt == 0) { + byte_count = + ep->dwc_ep.xfer_len - + ep->dwc_ep.xfer_count; + + ep->dwc_ep.xfer_buff += byte_count; + ep->dwc_ep.dma_addr += byte_count; + ep->dwc_ep.xfer_count += byte_count; + + DWC_DEBUGPL(DBG_PCDV, + "%d-%s len=%d xfersize=%d pktcnt=%d\n", + ep->dwc_ep.num, + (ep->dwc_ep. + is_in ? "IN" : "OUT"), + ep->dwc_ep.xfer_len, + deptsiz.b.xfersize, + deptsiz.b.pktcnt); + + if (ep->dwc_ep.xfer_len < + ep->dwc_ep.total_len) { + dwc_otg_ep_start_transfer + (core_if, &ep->dwc_ep); + } else if (ep->dwc_ep.sent_zlp) { + /* + * This fragment of code should initiate 0 + * length trasfer in case if it is queued + * a trasfer with size divisible to EPs max + * packet size and with usb_request zero field + * is set, which means that after data is transfered, + * it is also should be transfered + * a 0 length packet at the end. For Slave and + * Buffer DMA modes in this case SW has + * to initiate 2 transfers one with transfer size, + * and the second with 0 size. For Desriptor + * DMA mode SW is able to initiate a transfer, + * which will handle all the packets including + * the last 0 legth. + */ + ep->dwc_ep.sent_zlp = 0; + dwc_otg_ep_start_zl_transfer + (core_if, &ep->dwc_ep); + } else { + is_last = 1; + } + } else { + DWC_WARN + ("Incomplete transfer (%d - %s [siz=%d pkt=%d])\n", + ep->dwc_ep.num, + (ep->dwc_ep.is_in ? "IN" : "OUT"), + deptsiz.b.xfersize, + deptsiz.b.pktcnt); + } + } else { + dma_desc = ep->dwc_ep.desc_addr; + byte_count = 0; + ep->dwc_ep.sent_zlp = 0; + +#ifdef DWC_UTE_CFI + CFI_INFO("%s: BUFFER_MODE=%d\n", __func__, + ep->dwc_ep.buff_mode); + if (ep->dwc_ep.buff_mode != BM_STANDARD) { + int residue; + + residue = cfi_calc_desc_residue(ep); + if (residue < 0) + return; + + byte_count = residue; + } else { +#endif + for (i = 0; i < ep->dwc_ep.desc_cnt; + ++i) { + desc_sts = dma_desc->status; + byte_count += desc_sts.b.bytes; + dma_desc++; + } +#ifdef DWC_UTE_CFI + } +#endif + if (byte_count == 0) { + ep->dwc_ep.xfer_count = + ep->dwc_ep.total_len; + is_last = 1; + } else { + DWC_WARN("Incomplete transfer\n"); + } + } + } else { + if (deptsiz.b.xfersize == 0 && deptsiz.b.pktcnt == 0) { + DWC_DEBUGPL(DBG_PCDV, + "%d-%s len=%d xfersize=%d pktcnt=%d\n", + ep->dwc_ep.num, + ep->dwc_ep.is_in ? "IN" : "OUT", + ep->dwc_ep.xfer_len, + deptsiz.b.xfersize, + deptsiz.b.pktcnt); + + /* Check if the whole transfer was completed, + * if no, setup transfer for next portion of data + */ + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) { + dwc_otg_ep_start_transfer(core_if, + &ep->dwc_ep); + } else if (ep->dwc_ep.sent_zlp) { + /* + * This fragment of code should initiate 0 + * length trasfer in case if it is queued + * a trasfer with size divisible to EPs max + * packet size and with usb_request zero field + * is set, which means that after data is transfered, + * it is also should be transfered + * a 0 length packet at the end. For Slave and + * Buffer DMA modes in this case SW has + * to initiate 2 transfers one with transfer size, + * and the second with 0 size. For Desriptor + * DMA mode SW is able to initiate a transfer, + * which will handle all the packets including + * the last 0 legth. + */ + ep->dwc_ep.sent_zlp = 0; + dwc_otg_ep_start_zl_transfer(core_if, + &ep-> + dwc_ep); + } else { + is_last = 1; + } + } else { + DWC_WARN + ("Incomplete transfer (%d-%s [siz=%d pkt=%d])\n", + ep->dwc_ep.num, + (ep->dwc_ep.is_in ? "IN" : "OUT"), + deptsiz.b.xfersize, deptsiz.b.pktcnt); + } + } + } else { + dwc_otg_dev_out_ep_regs_t *out_ep_regs = + dev_if->out_ep_regs[ep->dwc_ep.num]; + desc_sts.d32 = 0; + if (core_if->dma_enable) { + if (core_if->dma_desc_enable) { + dma_desc = ep->dwc_ep.desc_addr; + byte_count = 0; + ep->dwc_ep.sent_zlp = 0; + +#ifdef DWC_UTE_CFI + CFI_INFO("%s: BUFFER_MODE=%d\n", __func__, + ep->dwc_ep.buff_mode); + if (ep->dwc_ep.buff_mode != BM_STANDARD) { + int residue; + residue = cfi_calc_desc_residue(ep); + if (residue < 0) + return; + byte_count = residue; + } else { +#endif + + for (i = 0; i < ep->dwc_ep.desc_cnt; + ++i) { + desc_sts = dma_desc->status; + byte_count += desc_sts.b.bytes; + dma_desc++; + } + +#ifdef DWC_UTE_CFI + } +#endif + ep->dwc_ep.xfer_count = ep->dwc_ep.total_len + - byte_count + + ((4 - (ep->dwc_ep.total_len & 0x3)) & 0x3); + is_last = 1; + } else { + deptsiz.d32 = 0; + deptsiz.d32 = + dwc_read_reg32(&out_ep_regs->doeptsiz); + + byte_count = (ep->dwc_ep.xfer_len - + ep->dwc_ep.xfer_count - + deptsiz.b.xfersize); + ep->dwc_ep.xfer_buff += byte_count; + ep->dwc_ep.dma_addr += byte_count; + ep->dwc_ep.xfer_count += byte_count; + + /* Check if the whole transfer was completed, + * if no, setup transfer for next portion of data + */ + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) { + dwc_otg_ep_start_transfer(core_if, + &ep->dwc_ep); + } else if (ep->dwc_ep.sent_zlp) { + /* + * This fragment of code should initiate 0 + * length trasfer in case if it is queued + * a trasfer with size divisible to EPs max + * packet size and with usb_request zero field + * is set, which means that after data is transfered, + * it is also should be transfered + * a 0 length packet at the end. For Slave and + * Buffer DMA modes in this case SW has + * to initiate 2 transfers one with transfer size, + * and the second with 0 size. For Desriptor + * DMA mode SW is able to initiate a transfer, + * which will handle all the packets including + * the last 0 legth. + */ + ep->dwc_ep.sent_zlp = 0; + dwc_otg_ep_start_zl_transfer(core_if, + &ep-> + dwc_ep); + } else { + is_last = 1; + } + } + } else { + /* Check if the whole transfer was completed, + * if no, setup transfer for next portion of data + */ + if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) { + dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep); + } else if (ep->dwc_ep.sent_zlp) { + /* + * This fragment of code should initiate 0 + * length trasfer in case if it is queued + * a trasfer with size divisible to EPs max + * packet size and with usb_request zero field + * is set, which means that after data is transfered, + * it is also should be transfered + * a 0 length packet at the end. For Slave and + * Buffer DMA modes in this case SW has + * to initiate 2 transfers one with transfer size, + * and the second with 0 size. For Desriptor + * DMA mode SW is able to initiate a transfer, + * which will handle all the packets including + * the last 0 legth. + */ + ep->dwc_ep.sent_zlp = 0; + dwc_otg_ep_start_zl_transfer(core_if, + &ep->dwc_ep); + } else { + is_last = 1; + } + } + + DWC_DEBUGPL(DBG_PCDV, + "addr %p, %d-%s len=%d cnt=%d xsize=%d pktcnt=%d\n", + &out_ep_regs->doeptsiz, ep->dwc_ep.num, + ep->dwc_ep.is_in ? "IN" : "OUT", + ep->dwc_ep.xfer_len, ep->dwc_ep.xfer_count, + deptsiz.b.xfersize, deptsiz.b.pktcnt); + } + + /* Complete the request */ + if (is_last) { +#ifdef DWC_UTE_CFI + if (ep->dwc_ep.buff_mode != BM_STANDARD) { + req->actual = ep->dwc_ep.cfi_req_len - byte_count; + } else { +#endif + req->actual = ep->dwc_ep.xfer_count; +#ifdef DWC_UTE_CFI + } +#endif + + dwc_otg_request_done(ep, req, 0); + + ep->dwc_ep.start_xfer_buff = 0; + ep->dwc_ep.xfer_buff = 0; + ep->dwc_ep.xfer_len = 0; + + /* If there is a request in the queue start it. */ + start_next_request(ep); + } +} + +#ifdef DWC_EN_ISOC + +/** + * This function BNA interrupt for Isochronous EPs + * + */ +static void dwc_otg_pcd_handle_iso_bna(dwc_otg_pcd_ep_t * ep) +{ + dwc_ep_t *dwc_ep = &ep->dwc_ep; + volatile uint32_t *addr; + depctl_data_t depctl = {.d32 = 0 }; + dwc_otg_pcd_t *pcd = ep->pcd; + dwc_otg_dev_dma_desc_t *dma_desc; + int i; + + dma_desc = + dwc_ep->iso_desc_addr + dwc_ep->desc_cnt * (dwc_ep->proc_buf_num); + + if (dwc_ep->is_in) { + dev_dma_desc_sts_t sts = {.d32 = 0 }; + for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) { + sts.d32 = dma_desc->status.d32; + sts.b_iso_in.bs = BS_HOST_READY; + dma_desc->status.d32 = sts.d32; + } + } else { + dev_dma_desc_sts_t sts = {.d32 = 0 }; + for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) { + sts.d32 = dma_desc->status.d32; + sts.b_iso_out.bs = BS_HOST_READY; + dma_desc->status.d32 = sts.d32; + } + } + + if (dwc_ep->is_in == 0) { + addr = + &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->num]-> + doepctl; + } else { + addr = + &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl; + } + depctl.b.epena = 1; + dwc_modify_reg32(addr, depctl.d32, depctl.d32); +} + +/** + * This function sets latest iso packet information(non-PTI mode) + * + * @param core_if Programming view of DWC_otg controller. + * @param ep The EP to start the transfer on. + * + */ +void set_current_pkt_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep) +{ + deptsiz_data_t deptsiz = {.d32 = 0 }; + dma_addr_t dma_addr; + uint32_t offset; + + if (ep->proc_buf_num) + dma_addr = ep->dma_addr1; + else + dma_addr = ep->dma_addr0; + + if (ep->is_in) { + deptsiz.d32 = + dwc_read_reg32(&core_if->dev_if->in_ep_regs[ep->num]-> + dieptsiz); + offset = ep->data_per_frame; + } else { + deptsiz.d32 = + dwc_read_reg32(&core_if->dev_if->out_ep_regs[ep->num]-> + doeptsiz); + offset = + ep->data_per_frame + + (0x4 & (0x4 - (ep->data_per_frame & 0x3))); + } + + if (!deptsiz.b.xfersize) { + ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame; + ep->pkt_info[ep->cur_pkt].offset = + ep->cur_pkt_dma_addr - dma_addr; + ep->pkt_info[ep->cur_pkt].status = 0; + } else { + ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame; + ep->pkt_info[ep->cur_pkt].offset = + ep->cur_pkt_dma_addr - dma_addr; + ep->pkt_info[ep->cur_pkt].status = -DWC_E_NO_DATA; + } + ep->cur_pkt_addr += offset; + ep->cur_pkt_dma_addr += offset; + ep->cur_pkt++; +} + +/** + * This function sets latest iso packet information(DDMA mode) + * + * @param core_if Programming view of DWC_otg controller. + * @param dwc_ep The EP to start the transfer on. + * + */ +static void set_ddma_iso_pkts_info(dwc_otg_core_if_t * core_if, + dwc_ep_t * dwc_ep) +{ + dwc_otg_dev_dma_desc_t *dma_desc; + dev_dma_desc_sts_t sts = {.d32 = 0 }; + iso_pkt_info_t *iso_packet; + uint32_t data_per_desc; + uint32_t offset; + int i, j; + + iso_packet = dwc_ep->pkt_info; + + /** Reinit closed DMA Descriptors*/ + /** ISO OUT EP */ + if (dwc_ep->is_in == 0) { + dma_desc = + dwc_ep->iso_desc_addr + + dwc_ep->desc_cnt * dwc_ep->proc_buf_num; + offset = 0; + + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm; + i += dwc_ep->pkt_per_frm) { + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) { + data_per_desc = + ((j + 1) * dwc_ep->maxpacket > + dwc_ep->data_per_frame) ? dwc_ep-> + data_per_frame - + j * dwc_ep->maxpacket : dwc_ep->maxpacket; + data_per_desc += + (data_per_desc % 4) ? (4 - + data_per_desc % + 4) : 0; + + sts.d32 = dma_desc->status.d32; + + /* Write status in iso_packet_decsriptor */ + iso_packet->status = + sts.b_iso_out.rxsts + + (sts.b_iso_out.bs ^ BS_DMA_DONE); + if (iso_packet->status) { + iso_packet->status = -DWC_E_NO_DATA; + } + + /* Received data length */ + if (!sts.b_iso_out.rxbytes) { + iso_packet->length = + data_per_desc - + sts.b_iso_out.rxbytes; + } else { + iso_packet->length = + data_per_desc - + sts.b_iso_out.rxbytes + (4 - + dwc_ep-> + data_per_frame + % 4); + } + + iso_packet->offset = offset; + + offset += data_per_desc; + dma_desc++; + iso_packet++; + } + } + + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) { + data_per_desc = + ((j + 1) * dwc_ep->maxpacket > + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame - + j * dwc_ep->maxpacket : dwc_ep->maxpacket; + data_per_desc += + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0; + + sts.d32 = dma_desc->status.d32; + + /* Write status in iso_packet_decsriptor */ + iso_packet->status = + sts.b_iso_out.rxsts + + (sts.b_iso_out.bs ^ BS_DMA_DONE); + if (iso_packet->status) { + iso_packet->status = -DWC_E_NO_DATA; + } + + /* Received data length */ + iso_packet->length = + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes; + + iso_packet->offset = offset; + + offset += data_per_desc; + iso_packet++; + dma_desc++; + } + + sts.d32 = dma_desc->status.d32; + + /* Write status in iso_packet_decsriptor */ + iso_packet->status = + sts.b_iso_out.rxsts + (sts.b_iso_out.bs ^ BS_DMA_DONE); + if (iso_packet->status) { + iso_packet->status = -DWC_E_NO_DATA; + } + /* Received data length */ + if (!sts.b_iso_out.rxbytes) { + iso_packet->length = + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes; + } else { + iso_packet->length = + dwc_ep->data_per_frame - sts.b_iso_out.rxbytes + + (4 - dwc_ep->data_per_frame % 4); + } + + iso_packet->offset = offset; + } else { +/** ISO IN EP */ + + dma_desc = + dwc_ep->iso_desc_addr + + dwc_ep->desc_cnt * dwc_ep->proc_buf_num; + + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) { + sts.d32 = dma_desc->status.d32; + + /* Write status in iso packet descriptor */ + iso_packet->status = + sts.b_iso_in.txsts + + (sts.b_iso_in.bs ^ BS_DMA_DONE); + if (iso_packet->status != 0) { + iso_packet->status = -DWC_E_NO_DATA; + + } + /* Bytes has been transfered */ + iso_packet->length = + dwc_ep->data_per_frame - sts.b_iso_in.txbytes; + + dma_desc++; + iso_packet++; + } + + sts.d32 = dma_desc->status.d32; + while (sts.b_iso_in.bs == BS_DMA_BUSY) { + sts.d32 = dma_desc->status.d32; + } + + /* Write status in iso packet descriptor ??? do be done with ERROR codes */ + iso_packet->status = + sts.b_iso_in.txsts + (sts.b_iso_in.bs ^ BS_DMA_DONE); + if (iso_packet->status != 0) { + iso_packet->status = -DWC_E_NO_DATA; + } + + /* Bytes has been transfered */ + iso_packet->length = + dwc_ep->data_per_frame - sts.b_iso_in.txbytes; + } +} + +/** + * This function reinitialize DMA Descriptors for Isochronous transfer + * + * @param core_if Programming view of DWC_otg controller. + * @param dwc_ep The EP to start the transfer on. + * + */ +static void reinit_ddma_iso_xfer(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep) +{ + int i, j; + dwc_otg_dev_dma_desc_t *dma_desc; + dma_addr_t dma_ad; + volatile uint32_t *addr; + dev_dma_desc_sts_t sts = {.d32 = 0 }; + uint32_t data_per_desc; + + if (dwc_ep->is_in == 0) { + addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl; + } else { + addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl; + } + + if (dwc_ep->proc_buf_num == 0) { + /** Buffer 0 descriptors setup */ + dma_ad = dwc_ep->dma_addr0; + } else { + /** Buffer 1 descriptors setup */ + dma_ad = dwc_ep->dma_addr1; + } + + /** Reinit closed DMA Descriptors*/ + /** ISO OUT EP */ + if (dwc_ep->is_in == 0) { + dma_desc = + dwc_ep->iso_desc_addr + + dwc_ep->desc_cnt * dwc_ep->proc_buf_num; + + sts.b_iso_out.bs = BS_HOST_READY; + sts.b_iso_out.rxsts = 0; + sts.b_iso_out.l = 0; + sts.b_iso_out.sp = 0; + sts.b_iso_out.ioc = 0; + sts.b_iso_out.pid = 0; + sts.b_iso_out.framenum = 0; + + for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm; + i += dwc_ep->pkt_per_frm) { + for (j = 0; j < dwc_ep->pkt_per_frm; ++j) { + data_per_desc = + ((j + 1) * dwc_ep->maxpacket > + dwc_ep->data_per_frame) ? dwc_ep-> + data_per_frame - + j * dwc_ep->maxpacket : dwc_ep->maxpacket; + data_per_desc += + (data_per_desc % 4) ? (4 - + data_per_desc % + 4) : 0; + sts.b_iso_out.rxbytes = data_per_desc; + dma_desc->buf = dma_ad; + dma_desc->status.d32 = sts.d32; + + dma_ad += data_per_desc; + dma_desc++; + } + } + + for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) { + + data_per_desc = + ((j + 1) * dwc_ep->maxpacket > + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame - + j * dwc_ep->maxpacket : dwc_ep->maxpacket; + data_per_desc += + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0; + sts.b_iso_out.rxbytes = data_per_desc; + + dma_desc->buf = dma_ad; + dma_desc->status.d32 = sts.d32; + + dma_desc++; + dma_ad += data_per_desc; + } + + sts.b_iso_out.ioc = 1; + sts.b_iso_out.l = dwc_ep->proc_buf_num; + + data_per_desc = + ((j + 1) * dwc_ep->maxpacket > + dwc_ep->data_per_frame) ? dwc_ep->data_per_frame - + j * dwc_ep->maxpacket : dwc_ep->maxpacket; + data_per_desc += + (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0; + sts.b_iso_out.rxbytes = data_per_desc; + + dma_desc->buf = dma_ad; + dma_desc->status.d32 = sts.d32; + } else { +/** ISO IN EP */ + + dma_desc = + dwc_ep->iso_desc_addr + + dwc_ep->desc_cnt * dwc_ep->proc_buf_num; + + sts.b_iso_in.bs = BS_HOST_READY; + sts.b_iso_in.txsts = 0; + sts.b_iso_in.sp = 0; + sts.b_iso_in.ioc = 0; + sts.b_iso_in.pid = dwc_ep->pkt_per_frm; + sts.b_iso_in.framenum = dwc_ep->next_frame; + sts.b_iso_in.txbytes = dwc_ep->data_per_frame; + sts.b_iso_in.l = 0; + + for (i = 0; i < dwc_ep->desc_cnt - 1; i++) { + dma_desc->buf = dma_ad; + dma_desc->status.d32 = sts.d32; + + sts.b_iso_in.framenum += dwc_ep->bInterval; + dma_ad += dwc_ep->data_per_frame; + dma_desc++; + } + + sts.b_iso_in.ioc = 1; + sts.b_iso_in.l = dwc_ep->proc_buf_num; + + dma_desc->buf = dma_ad; + dma_desc->status.d32 = sts.d32; + + dwc_ep->next_frame = + sts.b_iso_in.framenum + dwc_ep->bInterval * 1; + } + dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1; +} + +/** + * This function is to handle Iso EP transfer complete interrupt + * in case Iso out packet was dropped + * + * @param core_if Programming view of DWC_otg controller. + * @param dwc_ep The EP for wihich transfer complete was asserted + * + */ +static uint32_t handle_iso_out_pkt_dropped(dwc_otg_core_if_t * core_if, + dwc_ep_t * dwc_ep) +{ + uint32_t dma_addr; + uint32_t drp_pkt; + uint32_t drp_pkt_cnt; + deptsiz_data_t deptsiz = {.d32 = 0 }; + depctl_data_t depctl = {.d32 = 0 }; + int i; + + deptsiz.d32 = + dwc_read_reg32(&core_if->dev_if->out_ep_regs[dwc_ep->num]-> + doeptsiz); + + drp_pkt = dwc_ep->pkt_cnt - deptsiz.b.pktcnt; + drp_pkt_cnt = dwc_ep->pkt_per_frm - (drp_pkt % dwc_ep->pkt_per_frm); + + /* Setting dropped packets status */ + for (i = 0; i < drp_pkt_cnt; ++i) { + dwc_ep->pkt_info[drp_pkt].status = -DWC_E_NO_DATA; + drp_pkt++; + deptsiz.b.pktcnt--; + } + + if (deptsiz.b.pktcnt > 0) { + deptsiz.b.xfersize = + dwc_ep->xfer_len - (dwc_ep->pkt_cnt - + deptsiz.b.pktcnt) * dwc_ep->maxpacket; + } else { + deptsiz.b.xfersize = 0; + deptsiz.b.pktcnt = 0; + } + + dwc_write_reg32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz, + deptsiz.d32); + + if (deptsiz.b.pktcnt > 0) { + if (dwc_ep->proc_buf_num) { + dma_addr = + dwc_ep->dma_addr1 + dwc_ep->xfer_len - + deptsiz.b.xfersize; + } else { + dma_addr = + dwc_ep->dma_addr0 + dwc_ep->xfer_len - + deptsiz.b.xfersize;; + } + + dwc_write_reg32(&core_if->dev_if->out_ep_regs[dwc_ep->num]-> + doepdma, dma_addr); + + /** Re-enable endpoint, clear nak */ + depctl.d32 = 0; + depctl.b.epena = 1; + depctl.b.cnak = 1; + + dwc_modify_reg32(&core_if->dev_if->out_ep_regs[dwc_ep->num]-> + doepctl, depctl.d32, depctl.d32); + return 0; + } else { + return 1; + } +} + +/** + * This function sets iso packets information(PTI mode) + * + * @param core_if Programming view of DWC_otg controller. + * @param ep The EP to start the transfer on. + * + */ +static uint32_t set_iso_pkts_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep) +{ + int i, j; + dma_addr_t dma_ad; + iso_pkt_info_t *packet_info = ep->pkt_info; + uint32_t offset; + uint32_t frame_data; + deptsiz_data_t deptsiz; + + if (ep->proc_buf_num == 0) { + /** Buffer 0 descriptors setup */ + dma_ad = ep->dma_addr0; + } else { + /** Buffer 1 descriptors setup */ + dma_ad = ep->dma_addr1; + } + + if (ep->is_in) { + deptsiz.d32 = + dwc_read_reg32(&core_if->dev_if->in_ep_regs[ep->num]-> + dieptsiz); + } else { + deptsiz.d32 = + dwc_read_reg32(&core_if->dev_if->out_ep_regs[ep->num]-> + doeptsiz); + } + + if (!deptsiz.b.xfersize) { + offset = 0; + for (i = 0; i < ep->pkt_cnt; i += ep->pkt_per_frm) { + frame_data = ep->data_per_frame; + for (j = 0; j < ep->pkt_per_frm; ++j) { + + /* Packet status - is not set as initially + * it is set to 0 and if packet was sent + successfully, status field will remain 0*/ + + /* Bytes has been transfered */ + packet_info->length = + (ep->maxpacket < + frame_data) ? ep->maxpacket : frame_data; + + /* Received packet offset */ + packet_info->offset = offset; + offset += packet_info->length; + frame_data -= packet_info->length; + + packet_info++; + } + } + return 1; + } else { + /* This is a workaround for in case of Transfer Complete with + * PktDrpSts interrupts merging - in this case Transfer complete + * interrupt for Isoc Out Endpoint is asserted without PktDrpSts + * set and with DOEPTSIZ register non zero. Investigations showed, + * that this happens when Out packet is dropped, but because of + * interrupts merging during first interrupt handling PktDrpSts + * bit is cleared and for next merged interrupts it is not reset. + * In this case SW hadles the interrupt as if PktDrpSts bit is set. + */ + if (ep->is_in) { + return 1; + } else { + return handle_iso_out_pkt_dropped(core_if, ep); + } + } +} + +/** + * This function is to handle Iso EP transfer complete interrupt + * + * @param pcd The PCD + * @param ep The EP for which transfer complete was asserted + * + */ +static void complete_iso_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep) +{ + dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd); + dwc_ep_t *dwc_ep = &ep->dwc_ep; + uint8_t is_last = 0; + + if(ep->dwc_ep.next_frame == 0xffffffff) { + DWC_WARN("Next frame is not set!\n"); + return; + } + + if (core_if->dma_enable) { + if (core_if->dma_desc_enable) { + set_ddma_iso_pkts_info(core_if, dwc_ep); + reinit_ddma_iso_xfer(core_if, dwc_ep); + is_last = 1; + } else { + if (core_if->pti_enh_enable) { + if (set_iso_pkts_info(core_if, dwc_ep)) { + dwc_ep->proc_buf_num = + (dwc_ep->proc_buf_num ^ 1) & 0x1; + dwc_otg_iso_ep_start_buf_transfer + (core_if, dwc_ep); + is_last = 1; + } + } else { + set_current_pkt_info(core_if, dwc_ep); + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) { + is_last = 1; + dwc_ep->cur_pkt = 0; + dwc_ep->proc_buf_num = + (dwc_ep->proc_buf_num ^ 1) & 0x1; + if (dwc_ep->proc_buf_num) { + dwc_ep->cur_pkt_addr = + dwc_ep->xfer_buff1; + dwc_ep->cur_pkt_dma_addr = + dwc_ep->dma_addr1; + } else { + dwc_ep->cur_pkt_addr = + dwc_ep->xfer_buff0; + dwc_ep->cur_pkt_dma_addr = + dwc_ep->dma_addr0; + } + + } + dwc_otg_iso_ep_start_frm_transfer(core_if, + dwc_ep); + } + } + } else { + set_current_pkt_info(core_if, dwc_ep); + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) { + is_last = 1; + dwc_ep->cur_pkt = 0; + dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1; + if (dwc_ep->proc_buf_num) { + dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff1; + dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr1; + } else { + dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff0; + dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr0; + } + + } + dwc_otg_iso_ep_start_frm_transfer(core_if, dwc_ep); + } + if (is_last) + dwc_otg_iso_buffer_done(pcd, ep, ep->iso_req_handle); +} +#endif /* DWC_EN_ISOC */ + +/** + * This function handles EP0 Control transfers. + * + * The state of the control tranfers are tracked in + * ep0state. + */ +static void handle_ep0(dwc_otg_pcd_t * pcd) +{ + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); + dwc_otg_pcd_ep_t *ep0 = &pcd->ep0; + dev_dma_desc_sts_t desc_sts; + deptsiz0_data_t deptsiz; + uint32_t byte_count; + +#ifdef DEBUG_EP0 + DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__); + print_ep0_state(pcd); +#endif + +// DWC_PRINTF("HANDLE EP0\n"); + + switch (pcd->ep0state) { + case EP0_DISCONNECT: + break; + + case EP0_IDLE: + pcd->request_config = 0; + + pcd_setup(pcd); + break; + + case EP0_IN_DATA_PHASE: +#ifdef DEBUG_EP0 + DWC_DEBUGPL(DBG_PCD, "DATA_IN EP%d-%s: type=%d, mps=%d\n", + ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"), + ep0->dwc_ep.type, ep0->dwc_ep.maxpacket); +#endif + + if (core_if->dma_enable != 0) { + /* + * For EP0 we can only program 1 packet at a time so we + * need to do the make calculations after each complete. + * Call write_packet to make the calculations, as in + * slave mode, and use those values to determine if we + * can complete. + */ + if (core_if->dma_desc_enable == 0) { + deptsiz.d32 = + dwc_read_reg32(&core_if->dev_if-> + in_ep_regs[0]->dieptsiz); + byte_count = + ep0->dwc_ep.xfer_len - deptsiz.b.xfersize; + } else { + desc_sts = + core_if->dev_if->in_desc_addr->status; + byte_count = + ep0->dwc_ep.xfer_len - desc_sts.b.bytes; + } + ep0->dwc_ep.xfer_count += byte_count; + ep0->dwc_ep.xfer_buff += byte_count; + ep0->dwc_ep.dma_addr += byte_count; + } + if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) { + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd), + &ep0->dwc_ep); + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n"); + } else if (ep0->dwc_ep.sent_zlp) { + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd), + &ep0->dwc_ep); + ep0->dwc_ep.sent_zlp = 0; + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n"); + } else { + ep0_complete_request(ep0); + DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n"); + } + break; + case EP0_OUT_DATA_PHASE: +#ifdef DEBUG_EP0 + DWC_DEBUGPL(DBG_PCD, "DATA_OUT EP%d-%s: type=%d, mps=%d\n", + ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"), + ep0->dwc_ep.type, ep0->dwc_ep.maxpacket); +#endif + if (core_if->dma_enable != 0) { + if (core_if->dma_desc_enable == 0) { + deptsiz.d32 = + dwc_read_reg32(&core_if->dev_if-> + out_ep_regs[0]->doeptsiz); + byte_count = + ep0->dwc_ep.maxpacket - deptsiz.b.xfersize; + } else { + desc_sts = + core_if->dev_if->out_desc_addr->status; + byte_count = + ep0->dwc_ep.maxpacket - desc_sts.b.bytes; + } + ep0->dwc_ep.xfer_count += byte_count; + ep0->dwc_ep.xfer_buff += byte_count; + ep0->dwc_ep.dma_addr += byte_count; + } + if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) { + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd), + &ep0->dwc_ep); + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n"); + } else if (ep0->dwc_ep.sent_zlp) { + dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd), + &ep0->dwc_ep); + ep0->dwc_ep.sent_zlp = 0; + DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n"); + } else { + ep0_complete_request(ep0); + DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n"); + } + break; + + case EP0_IN_STATUS_PHASE: + case EP0_OUT_STATUS_PHASE: + DWC_DEBUGPL(DBG_PCD, "CASE: EP0_STATUS\n"); + ep0_complete_request(ep0); + pcd->ep0state = EP0_IDLE; + ep0->stopped = 1; + ep0->dwc_ep.is_in = 0; /* OUT for next SETUP */ + + /* Prepare for more SETUP Packets */ + if (core_if->dma_enable) { + ep0_out_start(core_if, pcd); + } + break; + + case EP0_STALL: + DWC_ERROR("EP0 STALLed, should not get here pcd_setup()\n"); + break; + } +#ifdef DEBUG_EP0 + print_ep0_state(pcd); +#endif +} + +/** + * Restart transfer + */ +static void restart_transfer(dwc_otg_pcd_t * pcd, const uint32_t epnum) +{ + dwc_otg_core_if_t *core_if; + dwc_otg_dev_if_t *dev_if; + deptsiz_data_t dieptsiz = {.d32 = 0 }; + dwc_otg_pcd_ep_t *ep; + + ep = get_in_ep(pcd, epnum); + +#ifdef DWC_EN_ISOC + if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) { + return; + } +#endif /* DWC_EN_ISOC */ + + core_if = GET_CORE_IF(pcd); + dev_if = core_if->dev_if; + + dieptsiz.d32 = dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dieptsiz); + + DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x xfer_len=%0x" + " stopped=%d\n", ep->dwc_ep.xfer_buff, + ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len, ep->stopped); + /* + * If xfersize is 0 and pktcnt in not 0, resend the last packet. + */ + if (dieptsiz.b.pktcnt && dieptsiz.b.xfersize == 0 && + ep->dwc_ep.start_xfer_buff != 0) { + if (ep->dwc_ep.total_len <= ep->dwc_ep.maxpacket) { + ep->dwc_ep.xfer_count = 0; + ep->dwc_ep.xfer_buff = ep->dwc_ep.start_xfer_buff; + ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count; + } else { + ep->dwc_ep.xfer_count -= ep->dwc_ep.maxpacket; + /* convert packet size to dwords. */ + ep->dwc_ep.xfer_buff -= ep->dwc_ep.maxpacket; + ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count; + } + ep->stopped = 0; + DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x " + "xfer_len=%0x stopped=%d\n", + ep->dwc_ep.xfer_buff, + ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len, + ep->stopped); + if (epnum == 0) { + dwc_otg_ep0_start_transfer(core_if, &ep->dwc_ep); + } else { + dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep); + } + } +} + +/** + * handle the IN EP disable interrupt. + */ +static inline void handle_in_ep_disable_intr(dwc_otg_pcd_t * pcd, + const uint32_t epnum) +{ + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); + dwc_otg_dev_if_t *dev_if = core_if->dev_if; + deptsiz_data_t dieptsiz = {.d32 = 0 }; + dctl_data_t dctl = {.d32 = 0 }; + dwc_otg_pcd_ep_t *ep; + dwc_ep_t *dwc_ep; + + ep = get_in_ep(pcd, epnum); + dwc_ep = &ep->dwc_ep; + + if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) { + dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num); + return; + } + + DWC_DEBUGPL(DBG_PCD, "diepctl%d=%0x\n", epnum, + dwc_read_reg32(&dev_if->in_ep_regs[epnum]->diepctl)); + dieptsiz.d32 = dwc_read_reg32(&dev_if->in_ep_regs[epnum]->dieptsiz); + + DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n", + dieptsiz.b.pktcnt, dieptsiz.b.xfersize); + + if (ep->stopped) { + /* Flush the Tx FIFO */ + dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num); + /* Clear the Global IN NP NAK */ + dctl.d32 = 0; + dctl.b.cgnpinnak = 1; + dwc_modify_reg32(&dev_if->dev_global_regs->dctl, dctl.d32, 0); + /* Restart the transaction */ + if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) { + restart_transfer(pcd, epnum); + } + } else { + /* Restart the transaction */ + if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) { + restart_transfer(pcd, epnum); + } + DWC_DEBUGPL(DBG_ANY, "STOPPED!!!\n"); + } +} + +/** + * Handler for the IN EP timeout handshake interrupt. + */ +static inline void handle_in_ep_timeout_intr(dwc_otg_pcd_t * pcd, + const uint32_t epnum) +{ + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); + dwc_otg_dev_if_t *dev_if = core_if->dev_if; + +#ifdef DEBUG + deptsiz_data_t dieptsiz = {.d32 = 0 }; + uint32_t num = 0; +#endif + dctl_data_t dctl = {.d32 = 0 }; + dwc_otg_pcd_ep_t *ep; + + gintmsk_data_t intr_mask = {.d32 = 0 }; + + ep = get_in_ep(pcd, epnum); + + /* Disable the NP Tx Fifo Empty Interrrupt */ + if (!core_if->dma_enable) { + intr_mask.b.nptxfempty = 1; + dwc_modify_reg32(&core_if->core_global_regs->gintmsk, + intr_mask.d32, 0); + } + /** @todo NGS Check EP type. + * Implement for Periodic EPs */ + /* + * Non-periodic EP + */ + /* Enable the Global IN NAK Effective Interrupt */ + intr_mask.b.ginnakeff = 1; + dwc_modify_reg32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32); + + /* Set Global IN NAK */ + dctl.b.sgnpinnak = 1; + dwc_modify_reg32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32); + + ep->stopped = 1; + +#ifdef DEBUG + dieptsiz.d32 = dwc_read_reg32(&dev_if->in_ep_regs[num]->dieptsiz); + DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n", + dieptsiz.b.pktcnt, dieptsiz.b.xfersize); +#endif + +#ifdef DISABLE_PERIODIC_EP + /* + * Set the NAK bit for this EP to + * start the disable process. + */ + diepctl.d32 = 0; + diepctl.b.snak = 1; + dwc_modify_reg32(&dev_if->in_ep_regs[num]->diepctl, diepctl.d32, + diepctl.d32); + ep->disabling = 1; + ep->stopped = 1; +#endif +} + +/** + * Handler for the IN EP NAK interrupt. + */ +static inline int32_t handle_in_ep_nak_intr(dwc_otg_pcd_t * pcd, + const uint32_t epnum) +{ + /** @todo implement ISR */ + dwc_otg_core_if_t *core_if; + diepmsk_data_t intr_mask = {.d32 = 0 }; + + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "IN EP NAK"); + core_if = GET_CORE_IF(pcd); + intr_mask.b.nak = 1; + + if (core_if->multiproc_int_enable) { + dwc_modify_reg32(&core_if->dev_if->dev_global_regs-> + diepeachintmsk[epnum], intr_mask.d32, 0); + } else { + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->diepmsk, + intr_mask.d32, 0); + } + + return 1; +} + +/** + * Handler for the OUT EP Babble interrupt. + */ +static inline int32_t handle_out_ep_babble_intr(dwc_otg_pcd_t * pcd, + const uint32_t epnum) +{ + /** @todo implement ISR */ + dwc_otg_core_if_t *core_if; + doepmsk_data_t intr_mask = {.d32 = 0 }; + + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", + "OUT EP Babble"); + core_if = GET_CORE_IF(pcd); + intr_mask.b.babble = 1; + + if (core_if->multiproc_int_enable) { + dwc_modify_reg32(&core_if->dev_if->dev_global_regs-> + doepeachintmsk[epnum], intr_mask.d32, 0); + } else { + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->doepmsk, + intr_mask.d32, 0); + } + + return 1; +} + +/** + * Handler for the OUT EP NAK interrupt. + */ +static inline int32_t handle_out_ep_nak_intr(dwc_otg_pcd_t * pcd, + const uint32_t epnum) +{ + /** @todo implement ISR */ + dwc_otg_core_if_t *core_if; + doepmsk_data_t intr_mask = {.d32 = 0 }; + + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "OUT EP NAK"); + core_if = GET_CORE_IF(pcd); + intr_mask.b.nak = 1; + + if (core_if->multiproc_int_enable) { + dwc_modify_reg32(&core_if->dev_if->dev_global_regs-> + doepeachintmsk[epnum], intr_mask.d32, 0); + } else { + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->doepmsk, + intr_mask.d32, 0); + } + + return 1; +} + +/** + * Handler for the OUT EP NYET interrupt. + */ +static inline int32_t handle_out_ep_nyet_intr(dwc_otg_pcd_t * pcd, + const uint32_t epnum) +{ + /** @todo implement ISR */ + dwc_otg_core_if_t *core_if; + doepmsk_data_t intr_mask = {.d32 = 0 }; + + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "OUT EP NYET"); + core_if = GET_CORE_IF(pcd); + intr_mask.b.nyet = 1; + + if (core_if->multiproc_int_enable) { + dwc_modify_reg32(&core_if->dev_if->dev_global_regs-> + doepeachintmsk[epnum], intr_mask.d32, 0); + } else { + dwc_modify_reg32(&core_if->dev_if->dev_global_regs->doepmsk, + intr_mask.d32, 0); + } + + return 1; +} + +/** + * This interrupt indicates that an IN EP has a pending Interrupt. + * The sequence for handling the IN EP interrupt is shown below: + * -# Read the Device All Endpoint Interrupt register + * -# Repeat the following for each IN EP interrupt bit set (from + * LSB to MSB). + * -# Read the Device Endpoint Interrupt (DIEPINTn) register + * -# If "Transfer Complete" call the request complete function + * -# If "Endpoint Disabled" complete the EP disable procedure. + * -# If "AHB Error Interrupt" log error + * -# If "Time-out Handshake" log error + * -# If "IN Token Received when TxFIFO Empty" write packet to Tx + * FIFO. + * -# If "IN Token EP Mismatch" (disable, this is handled by EP + * Mismatch Interrupt) + */ +static int32_t dwc_otg_pcd_handle_in_ep_intr(dwc_otg_pcd_t * pcd) +{ +#define CLEAR_IN_EP_INTR(__core_if,__epnum,__intr) \ +do { \ + diepint_data_t diepint = {.d32=0}; \ + diepint.b.__intr = 1; \ + dwc_write_reg32(&__core_if->dev_if->in_ep_regs[__epnum]->diepint, \ + diepint.d32); \ +} while (0) + + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); + dwc_otg_dev_if_t *dev_if = core_if->dev_if; + diepint_data_t diepint = {.d32 = 0 }; + dctl_data_t dctl = {.d32 = 0 }; + depctl_data_t depctl = {.d32 = 0 }; + uint32_t ep_intr; + uint32_t epnum = 0; + dwc_otg_pcd_ep_t *ep; + dwc_ep_t *dwc_ep; + gintmsk_data_t intr_mask = {.d32 = 0 }; + + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, pcd); + + /* Read in the device interrupt bits */ + ep_intr = dwc_otg_read_dev_all_in_ep_intr(core_if); + + /* Service the Device IN interrupts for each endpoint */ + while (ep_intr) { + if (ep_intr & 0x1) { + uint32_t empty_msk; + /* Get EP pointer */ + ep = get_in_ep(pcd, epnum); + dwc_ep = &ep->dwc_ep; + + depctl.d32 = + dwc_read_reg32(&dev_if->in_ep_regs[epnum]->diepctl); + empty_msk = + dwc_read_reg32(&dev_if->dev_global_regs-> + dtknqr4_fifoemptymsk); + + DWC_DEBUGPL(DBG_PCDV, + "IN EP INTERRUPT - %d\nepmty_msk - %8x diepctl - %8x\n", + epnum, empty_msk, depctl.d32); + + DWC_DEBUGPL(DBG_PCD, + "EP%d-%s: type=%d, mps=%d\n", + dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"), + dwc_ep->type, dwc_ep->maxpacket); + + diepint.d32 = + dwc_otg_read_dev_in_ep_intr(core_if, dwc_ep); + + DWC_DEBUGPL(DBG_PCDV, + "EP %d Interrupt Register - 0x%x\n", epnum, + diepint.d32); + /* Transfer complete */ + if (diepint.b.xfercompl) { + /* Disable the NP Tx FIFO Empty + * Interrrupt */ + if (core_if->en_multiple_tx_fifo == 0) { + intr_mask.b.nptxfempty = 1; + dwc_modify_reg32(&core_if-> + core_global_regs-> + gintmsk, intr_mask.d32, + 0); + } else { + /* Disable the Tx FIFO Empty Interrupt for this EP */ + uint32_t fifoemptymsk = + 0x1 << dwc_ep->num; + dwc_modify_reg32(&core_if->dev_if-> + dev_global_regs-> + dtknqr4_fifoemptymsk, + fifoemptymsk, 0); + } + /* Clear the bit in DIEPINTn for this interrupt */ + CLEAR_IN_EP_INTR(core_if, epnum, xfercompl); + + /* Complete the transfer */ + if (epnum == 0) { + handle_ep0(pcd); + } +#ifdef DWC_EN_ISOC + else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) { + if (!ep->stopped) + complete_iso_ep(pcd, ep); + } +#endif /* DWC_EN_ISOC */ + else { + + complete_ep(ep); + } + } + /* Endpoint disable */ + if (diepint.b.epdisabled) { + DWC_DEBUGPL(DBG_ANY, "EP%d IN disabled\n", + epnum); + handle_in_ep_disable_intr(pcd, epnum); + + /* Clear the bit in DIEPINTn for this interrupt */ + CLEAR_IN_EP_INTR(core_if, epnum, epdisabled); + } + /* AHB Error */ + if (diepint.b.ahberr) { + DWC_DEBUGPL(DBG_ANY, "EP%d IN AHB Error\n", + epnum); + /* Clear the bit in DIEPINTn for this interrupt */ + CLEAR_IN_EP_INTR(core_if, epnum, ahberr); + } + /* TimeOUT Handshake (non-ISOC IN EPs) */ + if (diepint.b.timeout) { + DWC_DEBUGPL(DBG_ANY, "EP%d IN Time-out\n", + epnum); + handle_in_ep_timeout_intr(pcd, epnum); + + CLEAR_IN_EP_INTR(core_if, epnum, timeout); + } + /** IN Token received with TxF Empty */ + if (diepint.b.intktxfemp) { + DWC_DEBUGPL(DBG_ANY, + "EP%d IN TKN TxFifo Empty\n", + epnum); + if (!ep->stopped && epnum != 0) { + + diepmsk_data_t diepmsk = {.d32 = 0 }; + diepmsk.b.intktxfemp = 1; + + if (core_if->multiproc_int_enable) { + dwc_modify_reg32(&dev_if-> + dev_global_regs-> + diepeachintmsk + [epnum], + diepmsk.d32, + 0); + } else { + dwc_modify_reg32(&dev_if-> + dev_global_regs-> + diepmsk, + diepmsk.d32, + 0); + } + } else if (core_if->dma_desc_enable + && epnum == 0 + && pcd->ep0state == + EP0_OUT_STATUS_PHASE) { + // EP0 IN set STALL + depctl.d32 = + dwc_read_reg32(&dev_if-> + in_ep_regs[epnum]-> + diepctl); + + /* set the disable and stall bits */ + if (depctl.b.epena) { + depctl.b.epdis = 1; + } + depctl.b.stall = 1; + dwc_write_reg32(&dev_if-> + in_ep_regs[epnum]-> + diepctl, depctl.d32); + } + CLEAR_IN_EP_INTR(core_if, epnum, intktxfemp); + } + /** IN Token Received with EP mismatch */ + if (diepint.b.intknepmis) { + DWC_DEBUGPL(DBG_ANY, + "EP%d IN TKN EP Mismatch\n", epnum); + CLEAR_IN_EP_INTR(core_if, epnum, intknepmis); + } + /** IN Endpoint NAK Effective */ + if (diepint.b.inepnakeff) { + DWC_DEBUGPL(DBG_ANY, + "EP%d IN EP NAK Effective\n", + epnum); + /* Periodic EP */ + if (ep->disabling) { + depctl.d32 = 0; + depctl.b.snak = 1; + depctl.b.epdis = 1; + dwc_modify_reg32(&dev_if-> + in_ep_regs[epnum]-> + diepctl, depctl.d32, + depctl.d32); + } + CLEAR_IN_EP_INTR(core_if, epnum, inepnakeff); + + } + + /** IN EP Tx FIFO Empty Intr */ + if (diepint.b.emptyintr) { + DWC_DEBUGPL(DBG_ANY, + "EP%d Tx FIFO Empty Intr \n", + epnum); + write_empty_tx_fifo(pcd, epnum); + + CLEAR_IN_EP_INTR(core_if, epnum, emptyintr); + + } + + /** IN EP BNA Intr */ + if (diepint.b.bna) { + CLEAR_IN_EP_INTR(core_if, epnum, bna); + if (core_if->dma_desc_enable) { +#ifdef DWC_EN_ISOC + if (dwc_ep->type == + DWC_OTG_EP_TYPE_ISOC) { + /* + * This checking is performed to prevent first "false" BNA + * handling occuring right after reconnect + */ + if (dwc_ep->next_frame != + 0xffffffff) + dwc_otg_pcd_handle_iso_bna + (ep); + } else +#endif /* DWC_EN_ISOC */ + { + dctl.d32 = + dwc_read_reg32(&dev_if-> + dev_global_regs-> + dctl); + + /* If Global Continue on BNA is disabled - disable EP */ + if (!dctl.b.gcontbna) { + depctl.d32 = 0; + depctl.b.snak = 1; + depctl.b.epdis = 1; + dwc_modify_reg32 + (&dev_if-> + in_ep_regs[epnum]-> + diepctl, + depctl.d32, + depctl.d32); + } else { + start_next_request(ep); + } + } + } + } + /* NAK Interrutp */ + if (diepint.b.nak) { + DWC_DEBUGPL(DBG_ANY, "EP%d IN NAK Interrupt\n", + epnum); + handle_in_ep_nak_intr(pcd, epnum); + + CLEAR_IN_EP_INTR(core_if, epnum, nak); + } + } + epnum++; + ep_intr >>= 1; + } + + return 1; +#undef CLEAR_IN_EP_INTR +} + +/** + * This interrupt indicates that an OUT EP has a pending Interrupt. + * The sequence for handling the OUT EP interrupt is shown below: + * -# Read the Device All Endpoint Interrupt register + * -# Repeat the following for each OUT EP interrupt bit set (from + * LSB to MSB). + * -# Read the Device Endpoint Interrupt (DOEPINTn) register + * -# If "Transfer Complete" call the request complete function + * -# If "Endpoint Disabled" complete the EP disable procedure. + * -# If "AHB Error Interrupt" log error + * -# If "Setup Phase Done" process Setup Packet (See Standard USB + * Command Processing) + */ +static int32_t dwc_otg_pcd_handle_out_ep_intr(dwc_otg_pcd_t * pcd) +{ +#define CLEAR_OUT_EP_INTR(__core_if,__epnum,__intr) \ +do { \ + doepint_data_t doepint = {.d32=0}; \ + doepint.b.__intr = 1; \ + dwc_write_reg32(&__core_if->dev_if->out_ep_regs[__epnum]->doepint, \ + doepint.d32); \ +} while (0) + + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); + dwc_otg_dev_if_t *dev_if = core_if->dev_if; + uint32_t ep_intr; + doepint_data_t doepint = {.d32 = 0 }; + dctl_data_t dctl = {.d32 = 0 }; + depctl_data_t doepctl = {.d32 = 0 }; + uint32_t epnum = 0; + dwc_otg_pcd_ep_t *ep; + dwc_ep_t *dwc_ep; + + DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__); + + /* Read in the device interrupt bits */ + ep_intr = dwc_otg_read_dev_all_out_ep_intr(core_if); + + while (ep_intr) { + if (ep_intr & 0x1) { + /* Get EP pointer */ + ep = get_out_ep(pcd, epnum); + dwc_ep = &ep->dwc_ep; + +#ifdef VERBOSE + DWC_DEBUGPL(DBG_PCDV, + "EP%d-%s: type=%d, mps=%d\n", + dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"), + dwc_ep->type, dwc_ep->maxpacket); +#endif + doepint.d32 = + dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep); + + /* Transfer complete */ + if (doepint.b.xfercompl) { + + if (epnum == 0) { + /* Clear the bit in DOEPINTn for this interrupt */ + CLEAR_OUT_EP_INTR(core_if, epnum, + xfercompl); + if (core_if->dma_desc_enable == 0 + || pcd->ep0state != EP0_IDLE) + handle_ep0(pcd); +#ifdef DWC_EN_ISOC + } else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) { + if (doepint.b.pktdrpsts == 0) { + /* Clear the bit in DOEPINTn for this interrupt */ + CLEAR_OUT_EP_INTR(core_if, + epnum, + xfercompl); + complete_iso_ep(pcd, ep); + } else { + + doepint_data_t doepint = {.d32 = + 0 }; + doepint.b.xfercompl = 1; + doepint.b.pktdrpsts = 1; + dwc_write_reg32(&core_if-> + dev_if-> + out_ep_regs + [epnum]-> + doepint, + doepint.d32); + if (handle_iso_out_pkt_dropped + (core_if, dwc_ep)) { + complete_iso_ep(pcd, + ep); + } + } +#endif /* DWC_EN_ISOC */ + } else { + /* Clear the bit in DOEPINTn for this interrupt */ + CLEAR_OUT_EP_INTR(core_if, epnum, + xfercompl); + complete_ep(ep); + } + + } + + /* Endpoint disable */ + if (doepint.b.epdisabled) { + + /* Clear the bit in DOEPINTn for this interrupt */ + CLEAR_OUT_EP_INTR(core_if, epnum, epdisabled); + } + /* AHB Error */ + if (doepint.b.ahberr) { + DWC_DEBUGPL(DBG_PCD, "EP%d OUT AHB Error\n", + epnum); + DWC_DEBUGPL(DBG_PCD, "EP DMA REG %d \n", + core_if->dev_if-> + out_ep_regs[epnum]->doepdma); + CLEAR_OUT_EP_INTR(core_if, epnum, ahberr); + } + /* Setup Phase Done (contorl EPs) */ + if (doepint.b.setup) { +#ifdef DEBUG_EP0 + DWC_DEBUGPL(DBG_PCD, "EP%d SETUP Done\n", + epnum); +#endif + CLEAR_OUT_EP_INTR(core_if, epnum, setup); + + handle_ep0(pcd); + } + + /** OUT EP BNA Intr */ + if (doepint.b.bna) { + CLEAR_OUT_EP_INTR(core_if, epnum, bna); + if (core_if->dma_desc_enable) { +#ifdef DWC_EN_ISOC + if (dwc_ep->type == + DWC_OTG_EP_TYPE_ISOC) { + /* + * This checking is performed to prevent first "false" BNA + * handling occuring right after reconnect + */ + if (dwc_ep->next_frame != + 0xffffffff) + dwc_otg_pcd_handle_iso_bna + (ep); + } else +#endif /* DWC_EN_ISOC */ + { + dctl.d32 = + dwc_read_reg32(&dev_if-> + dev_global_regs-> + dctl); + + /* If Global Continue on BNA is disabled - disable EP */ + if (!dctl.b.gcontbna) { + doepctl.d32 = 0; + doepctl.b.snak = 1; + doepctl.b.epdis = 1; + dwc_modify_reg32 + (&dev_if-> + out_ep_regs + [epnum]->doepctl, + doepctl.d32, + doepctl.d32); + } else { + start_next_request(ep); + } + } + } + } + if (doepint.b.stsphsercvd) { + CLEAR_OUT_EP_INTR(core_if, epnum, stsphsercvd); + if (core_if->dma_desc_enable) { + do_setup_in_status_phase(pcd); + } + } + /* Babble Interrutp */ + if (doepint.b.babble) { + DWC_DEBUGPL(DBG_ANY, "EP%d OUT Babble\n", + epnum); + handle_out_ep_babble_intr(pcd, epnum); + + CLEAR_OUT_EP_INTR(core_if, epnum, babble); + } + /* NAK Interrutp */ + if (doepint.b.nak) { + DWC_DEBUGPL(DBG_ANY, "EP%d OUT NAK\n", epnum); + handle_out_ep_nak_intr(pcd, epnum); + + CLEAR_OUT_EP_INTR(core_if, epnum, nak); + } + /* NYET Interrutp */ + if (doepint.b.nyet) { + DWC_DEBUGPL(DBG_ANY, "EP%d OUT NYET\n", epnum); + handle_out_ep_nyet_intr(pcd, epnum); + + CLEAR_OUT_EP_INTR(core_if, epnum, nyet); + } + } + + epnum++; + ep_intr >>= 1; + } + + return 1; + +#undef CLEAR_OUT_EP_INTR +} + +/** + * Incomplete ISO IN Transfer Interrupt. + * This interrupt indicates one of the following conditions occurred + * while transmitting an ISOC transaction. + * - Corrupted IN Token for ISOC EP. + * - Packet not complete in FIFO. + * The follow actions will be taken: + * -# Determine the EP + * -# Set incomplete flag in dwc_ep structure + * -# Disable EP; when "Endpoint Disabled" interrupt is received + * Flush FIFO + */ +int32_t dwc_otg_pcd_handle_incomplete_isoc_in_intr(dwc_otg_pcd_t * pcd) +{ + gintsts_data_t gintsts; + +#ifdef DWC_EN_ISOC + dwc_otg_dev_if_t *dev_if; + deptsiz_data_t deptsiz = {.d32 = 0 }; + depctl_data_t depctl = {.d32 = 0 }; + dsts_data_t dsts = {.d32 = 0 }; + dwc_ep_t *dwc_ep; + int i; + + dev_if = GET_CORE_IF(pcd)->dev_if; + + for (i = 1; i <= dev_if->num_in_eps; ++i) { + dwc_ep = &pcd->in_ep[i].dwc_ep; + if (dwc_ep->active && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) { + deptsiz.d32 = + dwc_read_reg32(&dev_if->in_ep_regs[i]->dieptsiz); + depctl.d32 = + dwc_read_reg32(&dev_if->in_ep_regs[i]->diepctl); + + if (depctl.b.epdis && deptsiz.d32) { + set_current_pkt_info(GET_CORE_IF(pcd), dwc_ep); + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) { + dwc_ep->cur_pkt = 0; + dwc_ep->proc_buf_num = + (dwc_ep->proc_buf_num ^ 1) & 0x1; + + if (dwc_ep->proc_buf_num) { + dwc_ep->cur_pkt_addr = + dwc_ep->xfer_buff1; + dwc_ep->cur_pkt_dma_addr = + dwc_ep->dma_addr1; + } else { + dwc_ep->cur_pkt_addr = + dwc_ep->xfer_buff0; + dwc_ep->cur_pkt_dma_addr = + dwc_ep->dma_addr0; + } + + } + + dsts.d32 = + dwc_read_reg32(&GET_CORE_IF(pcd)->dev_if-> + dev_global_regs->dsts); + dwc_ep->next_frame = dsts.b.soffn; + + dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF + (pcd), + dwc_ep); + } + } + } + +#else + gintmsk_data_t intr_mask = {.d32 = 0 }; + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", + "IN ISOC Incomplete"); + + intr_mask.b.incomplisoin = 1; + dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk, + intr_mask.d32, 0); +#endif //DWC_EN_ISOC + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.incomplisoin = 1; + dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts, + gintsts.d32); + + return 1; +} + +/** + * Incomplete ISO OUT Transfer Interrupt. + * + * This interrupt indicates that the core has dropped an ISO OUT + * packet. The following conditions can be the cause: + * - FIFO Full, the entire packet would not fit in the FIFO. + * - CRC Error + * - Corrupted Token + * The follow actions will be taken: + * -# Determine the EP + * -# Set incomplete flag in dwc_ep structure + * -# Read any data from the FIFO + * -# Disable EP. when "Endpoint Disabled" interrupt is received + * re-enable EP. + */ +int32_t dwc_otg_pcd_handle_incomplete_isoc_out_intr(dwc_otg_pcd_t * pcd) +{ + + gintsts_data_t gintsts; + +#ifdef DWC_EN_ISOC + dwc_otg_dev_if_t *dev_if; + deptsiz_data_t deptsiz = {.d32 = 0 }; + depctl_data_t depctl = {.d32 = 0 }; + dsts_data_t dsts = {.d32 = 0 }; + dwc_ep_t *dwc_ep; + int i; + + dev_if = GET_CORE_IF(pcd)->dev_if; + + for (i = 1; i <= dev_if->num_out_eps; ++i) { + dwc_ep = &pcd->in_ep[i].dwc_ep; + if (pcd->out_ep[i].dwc_ep.active && + pcd->out_ep[i].dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) { + deptsiz.d32 = + dwc_read_reg32(&dev_if->out_ep_regs[i]->doeptsiz); + depctl.d32 = + dwc_read_reg32(&dev_if->out_ep_regs[i]->doepctl); + + if (depctl.b.epdis && deptsiz.d32) { + set_current_pkt_info(GET_CORE_IF(pcd), + &pcd->out_ep[i].dwc_ep); + if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) { + dwc_ep->cur_pkt = 0; + dwc_ep->proc_buf_num = + (dwc_ep->proc_buf_num ^ 1) & 0x1; + + if (dwc_ep->proc_buf_num) { + dwc_ep->cur_pkt_addr = + dwc_ep->xfer_buff1; + dwc_ep->cur_pkt_dma_addr = + dwc_ep->dma_addr1; + } else { + dwc_ep->cur_pkt_addr = + dwc_ep->xfer_buff0; + dwc_ep->cur_pkt_dma_addr = + dwc_ep->dma_addr0; + } + + } + + dsts.d32 = + dwc_read_reg32(&GET_CORE_IF(pcd)->dev_if-> + dev_global_regs->dsts); + dwc_ep->next_frame = dsts.b.soffn; + + dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF + (pcd), + dwc_ep); + } + } + } +#else + /** @todo implement ISR */ + gintmsk_data_t intr_mask = {.d32 = 0 }; + + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", + "OUT ISOC Incomplete"); + + intr_mask.b.incomplisoout = 1; + dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk, + intr_mask.d32, 0); + +#endif /* DWC_EN_ISOC */ + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.incomplisoout = 1; + dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts, + gintsts.d32); + + return 1; +} + +/** + * This function handles the Global IN NAK Effective interrupt. + * + */ +int32_t dwc_otg_pcd_handle_in_nak_effective(dwc_otg_pcd_t * pcd) +{ + dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if; + depctl_data_t diepctl = {.d32 = 0 }; + depctl_data_t diepctl_rd = {.d32 = 0 }; + gintmsk_data_t intr_mask = {.d32 = 0 }; + gintsts_data_t gintsts; + int i; + + DWC_DEBUGPL(DBG_PCD, "Global IN NAK Effective\n"); + + /* Disable all active IN EPs */ + diepctl.b.epdis = 1; + diepctl.b.snak = 1; + + for (i = 0; i <= dev_if->num_in_eps; i++) { + diepctl_rd.d32 = + dwc_read_reg32(&dev_if->in_ep_regs[i]->diepctl); + if (diepctl_rd.b.epena) { + dwc_write_reg32(&dev_if->in_ep_regs[i]->diepctl, + diepctl.d32); + } + } + /* Disable the Global IN NAK Effective Interrupt */ + intr_mask.b.ginnakeff = 1; + dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk, + intr_mask.d32, 0); + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.ginnakeff = 1; + dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts, + gintsts.d32); + + return 1; +} + +/** + * OUT NAK Effective. + * + */ +int32_t dwc_otg_pcd_handle_out_nak_effective(dwc_otg_pcd_t * pcd) +{ + gintmsk_data_t intr_mask = {.d32 = 0 }; + gintsts_data_t gintsts; + + DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", + "Global IN NAK Effective\n"); + /* Disable the Global IN NAK Effective Interrupt */ + intr_mask.b.goutnakeff = 1; + dwc_modify_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk, + intr_mask.d32, 0); + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.goutnakeff = 1; + dwc_write_reg32(&GET_CORE_IF(pcd)->core_global_regs->gintsts, + gintsts.d32); + + return 1; +} + +/** + * PCD interrupt handler. + * + * The PCD handles the device interrupts. Many conditions can cause a + * device interrupt. When an interrupt occurs, the device interrupt + * service routine determines the cause of the interrupt and + * dispatches handling to the appropriate function. These interrupt + * handling functions are described below. + * + * All interrupt registers are processed from LSB to MSB. + * + */ +int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd) +{ + dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); +#ifdef VERBOSE + dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; +#endif + gintsts_data_t gintr_status; + int32_t retval = 0; + +#ifdef VERBOSE + DWC_DEBUGPL(DBG_ANY, "%s() gintsts=%08x gintmsk=%08x\n", + __func__, + dwc_read_reg32(&global_regs->gintsts), + dwc_read_reg32(&global_regs->gintmsk)); +#endif + + if (dwc_otg_is_device_mode(core_if)) { + DWC_SPINLOCK(pcd->lock); +#ifdef VERBOSE + DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%08x gintmsk=%08x\n", + __func__, + dwc_read_reg32(&global_regs->gintsts), + dwc_read_reg32(&global_regs->gintmsk)); +#endif + + gintr_status.d32 = dwc_otg_read_core_intr(core_if); + + DWC_DEBUGPL(DBG_PCDV, "%s: gintsts&gintmsk=%08x\n", + __func__, gintr_status.d32); + + if (gintr_status.b.sofintr) { + retval |= dwc_otg_pcd_handle_sof_intr(pcd); + } + if (gintr_status.b.rxstsqlvl) { + retval |= + dwc_otg_pcd_handle_rx_status_q_level_intr(pcd); + } + if (gintr_status.b.nptxfempty) { + retval |= dwc_otg_pcd_handle_np_tx_fifo_empty_intr(pcd); + } + if (gintr_status.b.ginnakeff) { + retval |= dwc_otg_pcd_handle_in_nak_effective(pcd); + } + if (gintr_status.b.goutnakeff) { + retval |= dwc_otg_pcd_handle_out_nak_effective(pcd); + } + if (gintr_status.b.i2cintr) { + retval |= dwc_otg_pcd_handle_i2c_intr(pcd); + } + if (gintr_status.b.erlysuspend) { + retval |= dwc_otg_pcd_handle_early_suspend_intr(pcd); + } + if (gintr_status.b.usbreset) { + retval |= dwc_otg_pcd_handle_usb_reset_intr(pcd); + } + if (gintr_status.b.enumdone) { + retval |= dwc_otg_pcd_handle_enum_done_intr(pcd); + } + if (gintr_status.b.isooutdrop) { + retval |= + dwc_otg_pcd_handle_isoc_out_packet_dropped_intr + (pcd); + } + if (gintr_status.b.eopframe) { + retval |= + dwc_otg_pcd_handle_end_periodic_frame_intr(pcd); + } + if (gintr_status.b.epmismatch) { + retval |= dwc_otg_pcd_handle_ep_mismatch_intr(core_if); + } + if (gintr_status.b.inepint) { + if (!core_if->multiproc_int_enable) { + retval |= dwc_otg_pcd_handle_in_ep_intr(pcd); + } + } + if (gintr_status.b.outepintr) { + if (!core_if->multiproc_int_enable) { + retval |= dwc_otg_pcd_handle_out_ep_intr(pcd); + } + } + if (gintr_status.b.incomplisoin) { + retval |= + dwc_otg_pcd_handle_incomplete_isoc_in_intr(pcd); + } + if (gintr_status.b.incomplisoout) { + retval |= + dwc_otg_pcd_handle_incomplete_isoc_out_intr(pcd); + } + + /* In MPI mode De vice Endpoints intterrupts are asserted + * without setting outepintr and inepint bits set, so these + * Interrupt handlers are called without checking these bit-fields + */ + if (core_if->multiproc_int_enable) { + retval |= dwc_otg_pcd_handle_in_ep_intr(pcd); + retval |= dwc_otg_pcd_handle_out_ep_intr(pcd); + } +#ifdef VERBOSE + DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%0x\n", __func__, + dwc_read_reg32(&global_regs->gintsts)); +#endif + DWC_SPINUNLOCK(pcd->lock); + } + return retval; +} + +#endif /* DWC_HOST_ONLY */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c new file mode 100644 index 000000000000..aae78a717f7e --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c @@ -0,0 +1,1288 @@ + /* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_linux.c $ + * $Revision: #7 $ + * $Date: 2009/04/03 $ + * $Change: 1225160 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ +#ifndef DWC_HOST_ONLY + +/** @file + * This file implements the Peripheral Controller Driver. + * + * The Peripheral Controller Driver (PCD) is responsible for + * translating requests from the Function Driver into the appropriate + * actions on the DWC_otg controller. It isolates the Function Driver + * from the specifics of the controller by providing an API to the + * Function Driver. + * + * The Peripheral Controller Driver for Linux will implement the + * Gadget API, so that the existing Gadget drivers can be used. + * (Gadget Driver is the Linux terminology for a Function Driver.) + * + * The Linux Gadget API is defined in the header file + * . The USB EP operations API is + * defined in the structure usb_ep_ops and the USB + * Controller API is defined in the structure + * usb_gadget_ops. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(LM_INTERFACE) +//# include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) +#include +#else +/* by 2.6.31, at least, the location of some headers has changed +*/ +#include +#endif + +#elif defined(PLATFORM_INTERFACE) +#include +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) +#include +#include +#include +#else +/* by 2.6.31, at least, the location of some headers has changed +*/ +#include +#include +#include +#endif + +#include + +#include "dwc_otg_pcd_if.h" +#include "dwc_otg_driver.h" +#include "dwc_otg_dbg.h" + +static struct gadget_wrapper { + dwc_otg_pcd_t *pcd; + + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + + struct usb_ep ep0; + struct usb_ep in_ep[16]; + struct usb_ep out_ep[16]; + +} *gadget_wrapper; + +/* Display the contents of the buffer */ +extern void dump_msg(const u8 * buf, unsigned int length); + +/* USB Endpoint Operations */ +/* + * The following sections briefly describe the behavior of the Gadget + * API endpoint operations implemented in the DWC_otg driver + * software. Detailed descriptions of the generic behavior of each of + * these functions can be found in the Linux header file + * include/linux/usb_gadget.h. + * + * The Gadget API provides wrapper functions for each of the function + * pointers defined in usb_ep_ops. The Gadget Driver calls the wrapper + * function, which then calls the underlying PCD function. The + * following sections are named according to the wrapper + * functions. Within each section, the corresponding DWC_otg PCD + * function name is specified. + * + */ + +/** + * This function is called by the Gadget Driver for each EP to be + * configured for the current configuration (SET_CONFIGURATION). + * + * This function initializes the dwc_otg_ep_t data structure, and then + * calls dwc_otg_ep_activate. + */ +static int ep_enable(struct usb_ep *usb_ep, + const struct usb_endpoint_descriptor *ep_desc) +{ + int retval; + + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, ep_desc); + + if (!usb_ep || !ep_desc || ep_desc->bDescriptorType != USB_DT_ENDPOINT) { + DWC_WARN("%s, bad ep or descriptor\n", __func__); + return -EINVAL; + } + if (usb_ep == &gadget_wrapper->ep0) { + DWC_WARN("%s, bad ep(0)\n", __func__); + return -EINVAL; + } + + /* Check FIFO size? */ + if (!ep_desc->wMaxPacketSize) { + DWC_WARN("%s, bad %s maxpacket\n", __func__, usb_ep->name); + return -ERANGE; + } + + if (!gadget_wrapper->driver || + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) { + DWC_WARN("%s, bogus device state\n", __func__); + return -ESHUTDOWN; + } + + retval = dwc_otg_pcd_ep_enable(gadget_wrapper->pcd, + (const uint8_t *)ep_desc, + (void *)usb_ep); + if (retval) { + DWC_WARN("dwc_otg_pcd_ep_enable failed\n"); + return -EINVAL; + } + + usb_ep->maxpacket = le16_to_cpu(ep_desc->wMaxPacketSize); + + return 0; +} + +/** + * This function is called when an EP is disabled due to disconnect or + * change in configuration. Any pending requests will terminate with a + * status of -ESHUTDOWN. + * + * This function modifies the dwc_otg_ep_t data structure for this EP, + * and then calls dwc_otg_ep_deactivate. + */ +static int ep_disable(struct usb_ep *usb_ep) +{ + int retval; + + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, usb_ep); + if (!usb_ep) { + DWC_DEBUGPL(DBG_PCD, "%s, %s not enabled\n", __func__, + usb_ep ? usb_ep->name : NULL); + return -EINVAL; + } + + retval = dwc_otg_pcd_ep_disable(gadget_wrapper->pcd, usb_ep); + if (retval) { + retval = -EINVAL; + } + + return retval; +} + +/** + * This function allocates a request object to use with the specified + * endpoint. + * + * @param ep The endpoint to be used with with the request + * @param gfp_flags the GFP_* flags to use. + */ +static struct usb_request *dwc_otg_pcd_alloc_request(struct usb_ep *ep, + gfp_t gfp_flags) +{ + struct usb_request *usb_req; + + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d)\n", __func__, ep, gfp_flags); + if (0 == ep) { + DWC_WARN("%s() %s\n", __func__, "Invalid EP!\n"); + return 0; + } + usb_req = kmalloc(sizeof(*usb_req), gfp_flags); + if (0 == usb_req) { + DWC_WARN("%s() %s\n", __func__, "request allocation failed!\n"); + return 0; + } + memset(usb_req, 0, sizeof(*usb_req)); + usb_req->dma = DWC_INVALID_DMA_ADDR; + + return usb_req; +} + +/** + * This function frees a request object. + * + * @param ep The endpoint associated with the request + * @param req The request being freed + */ +static void dwc_otg_pcd_free_request(struct usb_ep *ep, struct usb_request *req) +{ + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, ep, req); + + if (0 == ep || 0 == req) { + DWC_WARN("%s() %s\n", __func__, + "Invalid ep or req argument!\n"); + return; + } + + kfree(req); +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) +/** + * This function allocates an I/O buffer to be used for a transfer + * to/from the specified endpoint. + * + * @param usb_ep The endpoint to be used with with the request + * @param bytes The desired number of bytes for the buffer + * @param dma Pointer to the buffer's DMA address; must be valid + * @param gfp_flags the GFP_* flags to use. + * @return address of a new buffer or null is buffer could not be allocated. + */ +static void *dwc_otg_pcd_alloc_buffer(struct usb_ep *usb_ep, unsigned bytes, + dma_addr_t * dma, gfp_t gfp_flags) +{ + void *buf; + dwc_otg_pcd_t *pcd = 0; + + pcd = gadget_wrapper->pcd; + + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d,%p,%0x)\n", __func__, usb_ep, bytes, + dma, gfp_flags); + + /* Check dword alignment */ + if ((bytes & 0x3UL) != 0) { + DWC_WARN("%s() Buffer size is not a multiple of" + "DWORD size (%d)", __func__, bytes); + } + + buf = dma_alloc_coherent(NULL, bytes, dma, gfp_flags); + + /* Check dword alignment */ + if (((int)buf & 0x3UL) != 0) { + DWC_WARN("%s() Buffer is not DWORD aligned (%p)", + __func__, buf); + } + + return buf; +} + +/** + * This function frees an I/O buffer that was allocated by alloc_buffer. + * + * @param usb_ep the endpoint associated with the buffer + * @param buf address of the buffer + * @param dma The buffer's DMA address + * @param bytes The number of bytes of the buffer + */ +static void dwc_otg_pcd_free_buffer(struct usb_ep *usb_ep, void *buf, + dma_addr_t dma, unsigned bytes) +{ + dwc_otg_pcd_t *pcd = 0; + + pcd = gadget_wrapper->pcd; + + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%0x,%d)\n", __func__, buf, dma, bytes); + + dma_free_coherent(NULL, bytes, buf, dma); +} +#endif + +/** + * This function is used to submit an I/O Request to an EP. + * + * - When the request completes the request's completion callback + * is called to return the request to the driver. + * - An EP, except control EPs, may have multiple requests + * pending. + * - Once submitted the request cannot be examined or modified. + * - Each request is turned into one or more packets. + * - A BULK EP can queue any amount of data; the transfer is + * packetized. + * - Zero length Packets are specified with the request 'zero' + * flag. + */ +static int ep_queue(struct usb_ep *usb_ep, struct usb_request *usb_req, + gfp_t gfp_flags) +{ + dwc_otg_pcd_t *pcd; + int retval; + + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p,%d)\n", + __func__, usb_ep, usb_req, gfp_flags); + + if (!usb_req || !usb_req->complete || !usb_req->buf) { + DWC_WARN("bad params\n"); + return -EINVAL; + } + + if (!usb_ep) { + DWC_WARN("bad ep\n"); + return -EINVAL; + } + + pcd = gadget_wrapper->pcd; + if (!gadget_wrapper->driver || + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) { + DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n", + gadget_wrapper->gadget.speed); + DWC_WARN("bogus device state\n"); + return -ESHUTDOWN; + } + + DWC_DEBUGPL(DBG_PCD, "%s queue req %p, len %d buf %p\n", + usb_ep->name, usb_req, usb_req->length, usb_req->buf); + + usb_req->status = -EINPROGRESS; + usb_req->actual = 0; + + retval = dwc_otg_pcd_ep_queue(pcd, usb_ep, usb_req->buf, usb_req->dma, + usb_req->length, usb_req->zero, usb_req, + gfp_flags == GFP_ATOMIC ? 1 : 0); + if (retval) { + return -EINVAL; + } + + return 0; +} + +/** + * This function cancels an I/O request from an EP. + */ +static int ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req) +{ + DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, usb_req); + + if (!usb_ep || !usb_req) { + DWC_WARN("bad argument\n"); + return -EINVAL; + } + if (!gadget_wrapper->driver || + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) { + DWC_WARN("bogus device state\n"); + return -ESHUTDOWN; + } + if (dwc_otg_pcd_ep_dequeue(gadget_wrapper->pcd, usb_ep, usb_req)) { + return -EINVAL; + } + + return 0; +} + +/** + * usb_ep_set_halt stalls an endpoint. + * + * usb_ep_clear_halt clears an endpoint halt and resets its data + * toggle. + * + * Both of these functions are implemented with the same underlying + * function. The behavior depends on the value argument. + * + * @param[in] usb_ep the Endpoint to halt or clear halt. + * @param[in] value + * - 0 means clear_halt. + * - 1 means set_halt, + * - 2 means clear stall lock flag. + * - 3 means set stall lock flag. + */ +static int ep_halt(struct usb_ep *usb_ep, int value) +{ + int retval = 0; + + DWC_DEBUGPL(DBG_PCD, "HALT %s %d\n", usb_ep->name, value); + + if (!usb_ep) { + DWC_WARN("bad ep\n"); + return -EINVAL; + } + + retval = dwc_otg_pcd_ep_halt(gadget_wrapper->pcd, usb_ep, value); + if (retval == -DWC_E_AGAIN) { + return -EAGAIN; + } else if (retval) { + retval = -EINVAL; + } + + return retval; +} + +//#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)) +#if 0 +/** + * ep_wedge: sets the halt feature and ignores clear requests + * + * @usb_ep: the endpoint being wedged + * + * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT) + * requests. If the gadget driver clears the halt status, it will + * automatically unwedge the endpoint. + * + * Returns zero on success, else negative errno. * + * Check usb_ep_set_wedge() at "usb_gadget.h" for details + */ +static int ep_wedge(struct usb_ep *usb_ep) +{ + int retval = 0; + + DWC_DEBUGPL(DBG_PCD, "WEDGE %s\n", usb_ep->name); + + if (!usb_ep) { + DWC_WARN("bad ep\n"); + return -EINVAL; + } + + retval = dwc_otg_pcd_ep_wedge(gadget_wrapper->pcd, usb_ep); + if (retval == -DWC_E_AGAIN) { + retval = -EAGAIN; + } else if (retval) { + retval = -EINVAL; + } + + return retval; +} +#endif + +#ifdef DWC_EN_ISOC +/** + * This function is used to submit an ISOC Transfer Request to an EP. + * + * - Every time a sync period completes the request's completion callback + * is called to provide data to the gadget driver. + * - Once submitted the request cannot be modified. + * - Each request is turned into periodic data packets untill ISO + * Transfer is stopped.. + */ +static int iso_ep_start(struct usb_ep *usb_ep, struct usb_iso_request *req, + gfp_t gfp_flags) +{ + int retval = 0; + + if (!req || !req->process_buffer || !req->buf0 || !req->buf1) { + DWC_WARN("bad params\n"); + return -EINVAL; + } + + if (!usb_ep) { + DWC_PRINTF("bad params\n"); + return -EINVAL; + } + + req->status = -EINPROGRESS; + + retval = + dwc_otg_pcd_iso_ep_start(gadget_wrapper->pcd, usb_ep, req->buf0, + req->buf1, req->dma0, req->dma1, + req->sync_frame, req->data_pattern_frame, + req->data_per_frame, + req->flags & USB_REQ_ISO_ASAP ? -1 : req-> + start_frame, req->buf_proc_intrvl, req, + gfp_flags == GFP_ATOMIC ? 1 : 0); + + if (retval) { + return -EINVAL; + } + + return retval; +} + +/** + * This function stops ISO EP Periodic Data Transfer. + */ +static int iso_ep_stop(struct usb_ep *usb_ep, struct usb_iso_request *req) +{ + int retval = 0; + if (!usb_ep) { + DWC_WARN("bad ep\n"); + } + + if (!gadget_wrapper->driver || + gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) { + DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n", + gadget_wrapper->gadget.speed); + DWC_WARN("bogus device state\n"); + } + + dwc_otg_pcd_iso_ep_stop(gadget_wrapper->pcd, usb_ep, req); + if (retval) { + retval = -EINVAL; + } + + return retval; +} + +static struct usb_iso_request *alloc_iso_request(struct usb_ep *ep, + int packets, gfp_t gfp_flags) +{ + struct usb_iso_request *pReq = NULL; + uint32_t req_size; + + req_size = sizeof(struct usb_iso_request); + req_size += + (2 * packets * (sizeof(struct usb_gadget_iso_packet_descriptor))); + + pReq = kmalloc(req_size, gfp_flags); + if (!pReq) { + DWC_WARN("Can't allocate Iso Request\n"); + return 0; + } + pReq->iso_packet_desc0 = (void *)(pReq + 1); + + pReq->iso_packet_desc1 = pReq->iso_packet_desc0 + packets; + + return pReq; +} + +static void free_iso_request(struct usb_ep *ep, struct usb_iso_request *req) +{ + kfree(req); +} + +static struct usb_isoc_ep_ops dwc_otg_pcd_ep_ops = { + .ep_ops = { + .enable = ep_enable, + .disable = ep_disable, + + .alloc_request = dwc_otg_pcd_alloc_request, + .free_request = dwc_otg_pcd_free_request, + + .alloc_buffer = dwc_otg_pcd_alloc_buffer, + .free_buffer = dwc_otg_pcd_free_buffer, + + .queue = ep_queue, + .dequeue = ep_dequeue, + + .set_halt = ep_halt, + .fifo_status = 0, + .fifo_flush = 0, + }, + .iso_ep_start = iso_ep_start, + .iso_ep_stop = iso_ep_stop, + .alloc_iso_request = alloc_iso_request, + .free_iso_request = free_iso_request, +}; + +#else + + int (*enable) (struct usb_ep *ep, + const struct usb_endpoint_descriptor *desc); + int (*disable) (struct usb_ep *ep); + + struct usb_request *(*alloc_request) (struct usb_ep *ep, + gfp_t gfp_flags); + void (*free_request) (struct usb_ep *ep, struct usb_request *req); + + int (*queue) (struct usb_ep *ep, struct usb_request *req, + gfp_t gfp_flags); + int (*dequeue) (struct usb_ep *ep, struct usb_request *req); + + int (*set_halt) (struct usb_ep *ep, int value); + int (*set_wedge) (struct usb_ep *ep); + + int (*fifo_status) (struct usb_ep *ep); + void (*fifo_flush) (struct usb_ep *ep); +static struct usb_ep_ops dwc_otg_pcd_ep_ops = { + .enable = ep_enable, + .disable = ep_disable, + + .alloc_request = dwc_otg_pcd_alloc_request, + .free_request = dwc_otg_pcd_free_request, + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) + .alloc_buffer = dwc_otg_pcd_alloc_buffer, + .free_buffer = dwc_otg_pcd_free_buffer, +#else + /* .set_wedge = ep_wedge, */ + .set_wedge = NULL, /* uses set_halt instead */ +#endif + + .queue = ep_queue, + .dequeue = ep_dequeue, + + .set_halt = ep_halt, + .fifo_status = 0, + .fifo_flush = 0, + +}; + +#endif /* _EN_ISOC_ */ +/* Gadget Operations */ +/** + * The following gadget operations will be implemented in the DWC_otg + * PCD. Functions in the API that are not described below are not + * implemented. + * + * The Gadget API provides wrapper functions for each of the function + * pointers defined in usb_gadget_ops. The Gadget Driver calls the + * wrapper function, which then calls the underlying PCD function. The + * following sections are named according to the wrapper functions + * (except for ioctl, which doesn't have a wrapper function). Within + * each section, the corresponding DWC_otg PCD function name is + * specified. + * + */ + +/** + *Gets the USB Frame number of the last SOF. + */ +static int get_frame_number(struct usb_gadget *gadget) +{ + struct gadget_wrapper *d; + + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget); + + if (gadget == 0) { + return -ENODEV; + } + + d = container_of(gadget, struct gadget_wrapper, gadget); + return dwc_otg_pcd_get_frame_number(d->pcd); +} + +#ifdef CONFIG_USB_DWC_OTG_LPM +static int test_lpm_enabled(struct usb_gadget *gadget) +{ + struct gadget_wrapper *d; + + d = container_of(gadget, struct gadget_wrapper, gadget); + + return dwc_otg_pcd_is_lpm_enabled(d->pcd); +} +#endif + +/** + * Initiates Session Request Protocol (SRP) to wakeup the host if no + * session is in progress. If a session is already in progress, but + * the device is suspended, remote wakeup signaling is started. + * + */ +static int wakeup(struct usb_gadget *gadget) +{ + struct gadget_wrapper *d; + + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget); + + if (gadget == 0) { + return -ENODEV; + } else { + d = container_of(gadget, struct gadget_wrapper, gadget); + } + dwc_otg_pcd_wakeup(d->pcd); + return 0; +} + +static const struct usb_gadget_ops dwc_otg_pcd_ops = { + .get_frame = get_frame_number, + .wakeup = wakeup, +#ifdef CONFIG_USB_DWC_OTG_LPM + .lpm_support = test_lpm_enabled, +#endif + // current versions must always be self-powered +}; + +static int _setup(dwc_otg_pcd_t * pcd, uint8_t * bytes) +{ + int retval = -DWC_E_NOT_SUPPORTED; + if (gadget_wrapper->driver && gadget_wrapper->driver->setup) { + retval = gadget_wrapper->driver->setup(&gadget_wrapper->gadget, + (struct usb_ctrlrequest + *)bytes); + } + + if (retval == -ENOTSUPP) { + retval = -DWC_E_NOT_SUPPORTED; + } else if (retval < 0) { + retval = -DWC_E_INVALID; + } + + return retval; +} + +#ifdef DWC_EN_ISOC +static int _isoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle, + void *req_handle, int proc_buf_num) +{ + int i, packet_count; + struct usb_gadget_iso_packet_descriptor *iso_packet = 0; + struct usb_iso_request *iso_req = req_handle; + + if (proc_buf_num) { + iso_packet = iso_req->iso_packet_desc1; + } else { + iso_packet = iso_req->iso_packet_desc0; + } + packet_count = + dwc_otg_pcd_get_iso_packet_count(pcd, ep_handle, req_handle); + for (i = 0; i < packet_count; ++i) { + int status; + int actual; + int offset; + dwc_otg_pcd_get_iso_packet_params(pcd, ep_handle, req_handle, + i, &status, &actual, &offset); + switch (status) { + case -DWC_E_NO_DATA: + status = -ENODATA; + break; + default: + if (status) { + DWC_PRINTF("unknown status in isoc packet\n"); + } + + } + iso_packet[i].status = status; + iso_packet[i].offset = offset; + iso_packet[i].actual_length = actual; + } + + iso_req->status = 0; + iso_req->process_buffer(ep_handle, iso_req); + + return 0; +} +#endif /* DWC_EN_ISOC */ + +static int _complete(dwc_otg_pcd_t * pcd, void *ep_handle, + void *req_handle, int32_t status, uint32_t actual) +{ + struct usb_request *req = (struct usb_request *)req_handle; + + if (req && req->complete) { + switch (status) { + case -DWC_E_SHUTDOWN: + req->status = -ESHUTDOWN; + break; + case -DWC_E_RESTART: + req->status = -ECONNRESET; + break; + case -DWC_E_INVALID: + req->status = -EINVAL; + break; + case -DWC_E_TIMEOUT: + req->status = -ETIMEDOUT; + break; + default: + req->status = status; + + } + req->actual = actual; + req->complete(ep_handle, req); + } + + return 0; +} + +static int _connect(dwc_otg_pcd_t * pcd, int speed) +{ + gadget_wrapper->gadget.speed = speed; + return 0; +} + +static int _disconnect(dwc_otg_pcd_t * pcd) +{ + if (gadget_wrapper->driver && gadget_wrapper->driver->disconnect) { + gadget_wrapper->driver->disconnect(&gadget_wrapper->gadget); + } + return 0; +} + +static int _resume(dwc_otg_pcd_t * pcd) +{ + if (gadget_wrapper->driver && gadget_wrapper->driver->resume) { + gadget_wrapper->driver->resume(&gadget_wrapper->gadget); + } + + return 0; +} + +static int _suspend(dwc_otg_pcd_t * pcd) +{ + if (gadget_wrapper->driver && gadget_wrapper->driver->suspend) { + gadget_wrapper->driver->suspend(&gadget_wrapper->gadget); + } + return 0; +} + +/** + * This function updates the otg values in the gadget structure. + */ +static int _hnp_changed(dwc_otg_pcd_t * pcd) +{ + + if (!gadget_wrapper->gadget.is_otg) + return 0; + + gadget_wrapper->gadget.b_hnp_enable = get_b_hnp_enable(pcd); + gadget_wrapper->gadget.a_hnp_support = get_a_hnp_support(pcd); + gadget_wrapper->gadget.a_alt_hnp_support = get_a_alt_hnp_support(pcd); + return 0; +} + +static int _reset(dwc_otg_pcd_t * pcd) +{ + return 0; +} + +#ifdef DWC_UTE_CFI +static int _cfi_setup(dwc_otg_pcd_t * pcd, void *cfi_req) +{ + int retval = -DWC_E_INVALID; + if (gadget_wrapper->driver->cfi_feature_setup) { + retval = + gadget_wrapper->driver->cfi_feature_setup(&gadget_wrapper-> + gadget, + (struct + cfi_usb_ctrlrequest + *)cfi_req); + } + + return retval; +} +#endif + +static const struct dwc_otg_pcd_function_ops fops = { + .complete = _complete, +#ifdef DWC_EN_ISOC + .isoc_complete = _isoc_complete, +#endif + .setup = _setup, + .disconnect = _disconnect, + .connect = _connect, + .resume = _resume, + .suspend = _suspend, + .hnp_changed = _hnp_changed, + .reset = _reset, +#ifdef DWC_UTE_CFI + .cfi_setup = _cfi_setup, +#endif +}; + +/** + * This function is the top level PCD interrupt handler. + */ +static irqreturn_t dwc_otg_pcd_irq(int irq, void *dev) +{ + dwc_otg_pcd_t *pcd = dev; + int32_t retval = IRQ_NONE; + + retval = dwc_otg_pcd_handle_intr(pcd); + if (retval != 0) { + S3C2410X_CLEAR_EINTPEND(); + } + return IRQ_RETVAL(retval); +} + +/** + * This function initialized the usb_ep structures to there default + * state. + * + * @param d Pointer on gadget_wrapper. + */ +void gadget_add_eps(struct gadget_wrapper *d) +{ + static const char *names[] = { + + "ep0", + "ep1in", + "ep2in", + "ep3in", + "ep4in", + "ep5in", + "ep6in", + "ep7in", + "ep8in", + "ep9in", + "ep10in", + "ep11in", + "ep12in", + "ep13in", + "ep14in", + "ep15in", + "ep1out", + "ep2out", + "ep3out", + "ep4out", + "ep5out", + "ep6out", + "ep7out", + "ep8out", + "ep9out", + "ep10out", + "ep11out", + "ep12out", + "ep13out", + "ep14out", + "ep15out" + }; + + int i; + struct usb_ep *ep; + + DWC_DEBUGPL(DBG_PCDV, "%s\n", __func__); + + INIT_LIST_HEAD(&d->gadget.ep_list); + d->gadget.ep0 = &d->ep0; + d->gadget.speed = USB_SPEED_UNKNOWN; + + INIT_LIST_HEAD(&d->gadget.ep0->ep_list); + + /** + * Initialize the EP0 structure. + */ + ep = &d->ep0; + + /* Init the usb_ep structure. */ + ep->name = names[0]; + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops; + + /** + * @todo NGS: What should the max packet size be set to + * here? Before EP type is set? + */ + ep->maxpacket = MAX_PACKET_SIZE; + dwc_otg_pcd_ep_enable(d->pcd, NULL, ep); + + list_add_tail(&ep->ep_list, &d->gadget.ep_list); + + /** + * Initialize the EP structures. + */ + + for (i = 0; i < 15; i++) { + ep = &d->in_ep[i]; + + /* Init the usb_ep structure. */ + ep->name = names[i + 1]; + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops; + + /** + * @todo NGS: What should the max packet size be set to + * here? Before EP type is set? + */ + ep->maxpacket = MAX_PACKET_SIZE; + list_add_tail(&ep->ep_list, &d->gadget.ep_list); + } + + for (i = 0; i < 15; i++) { + ep = &d->out_ep[i]; + + /* Init the usb_ep structure. */ + ep->name = names[15 + i + 1]; + ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops; + + /** + * @todo NGS: What should the max packet size be set to + * here? Before EP type is set? + */ + ep->maxpacket = MAX_PACKET_SIZE; + + list_add_tail(&ep->ep_list, &d->gadget.ep_list); + } + + /* remove ep0 from the list. There is a ep0 pointer. */ + list_del_init(&d->ep0.ep_list); + + d->ep0.maxpacket = MAX_EP0_SIZE; +} + +/** + * This function releases the Gadget device. + * required by device_unregister(). + * + * @todo Should this do something? Should it free the PCD? + */ +static void dwc_otg_pcd_gadget_release(struct device *dev) +{ + DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, dev); +} + +static struct gadget_wrapper *alloc_wrapper( +#ifdef LM_INTERFACE + struct lm_device *_dev +#elif defined(PCI_INTERFACE) + struct pci_dev *_dev +#elif defined(PLATFORM_INTERFACE) + struct platform_device *_dev +#endif + ) +{ +#ifdef LM_INTERFACE + dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev); +#endif + static char pcd_name[] = "dwc_otg_pcd"; + + struct gadget_wrapper *d; + int retval; + + d = dwc_alloc(sizeof(*d)); + if (d == NULL) { + return NULL; + } + + memset(d, 0, sizeof(*d)); + + d->gadget.name = pcd_name; + d->pcd = otg_dev->pcd; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) + strcpy(d->gadget.dev.bus_id, "gadget"); +#else + /*d->gadget.dev.bus = NULL;*/ + d->gadget.dev.init_name = "gadget"; +#endif + d->gadget.dev.parent = &_dev->dev; + d->gadget.dev.release = dwc_otg_pcd_gadget_release; + d->gadget.ops = &dwc_otg_pcd_ops; + d->gadget.is_dualspeed = dwc_otg_pcd_is_dualspeed(otg_dev->pcd); + d->gadget.is_otg = dwc_otg_pcd_is_otg(otg_dev->pcd); + + d->driver = 0; + /* Register the gadget device */ + retval = device_register(&d->gadget.dev); + if (retval != 0) { + DWC_ERROR("device_register failed\n"); + dwc_free(d); + return NULL; + } + + return d; +} + +static void free_wrapper(struct gadget_wrapper *d) +{ + if (d->driver) { + /* should have been done already by driver model core */ + DWC_WARN("driver '%s' is still registered\n", + d->driver->driver.name); + usb_gadget_unregister_driver(d->driver); + } + + device_unregister(&d->gadget.dev); + dwc_free(d); +} + +/** + * This function initialized the PCD portion of the driver. + * + */ +int pcd_init( +#ifdef LM_INTERFACE + struct lm_device *_dev +#elif defined(PCI_INTERFACE) + struct pci_dev *_dev +#elif defined(PLATFORM_INTERFACE) + struct platform_device *_dev +#endif + ) + +{ +#ifdef LM_INTERFACE + dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev); +#endif + int devirq; + + int retval = 0; + + DWC_DEBUGPL(DBG_PCDV, "%s(%p) otg_dev=%p\n", __func__, _dev, otg_dev); + + otg_dev->pcd = dwc_otg_pcd_init(otg_dev->core_if); + + if (!otg_dev->pcd) { + DWC_ERROR("dwc_otg_pcd_init failed\n"); + return -ENOMEM; + } + + gadget_wrapper = alloc_wrapper(_dev); + + /* + * Initialize EP structures + */ + gadget_add_eps(gadget_wrapper); + + /* + * Setup interupt handler + */ +#ifdef PLATFORM_INTERFACE + devirq = platform_get_irq(_dev, 0); +#else + devirq = _dev->irq; +#endif + DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n", devirq); + retval = request_irq(devirq, dwc_otg_pcd_irq, + IRQF_SHARED, gadget_wrapper->gadget.name, + otg_dev->pcd); + if (retval != 0) { + DWC_ERROR("request of irq%d failed\n", devirq); + free_wrapper(gadget_wrapper); + return -EBUSY; + } + + dwc_otg_pcd_start(gadget_wrapper->pcd, &fops); + + return retval; +} + +/** + * Cleanup the PCD. + */ +void pcd_remove( +#ifdef LM_INTERFACE + struct lm_device *_dev +#elif defined(PCI_INTERFACE) + struct pci_dev *_dev +#elif defined(PLATFORM_INTERFACE) + struct platform_device *_dev +#endif + ) +{ +#ifdef LM_INTERFACE + dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev); +#elif defined(PCI_INTERFACE) + dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev); +#elif defined(PLATFORM_INTERFACE) + dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev); +#endif + dwc_otg_pcd_t *pcd = otg_dev->pcd; + + DWC_DEBUGPL(DBG_PCDV, "%s(%p) otg_dev %p\n", __func__, _dev, otg_dev); + + /* + * Free the IRQ + */ +#ifdef PLATFORM_INTERFACE + free_irq(platform_get_irq(_dev, 0), pcd); +#else + free_irq(_dev->irq, pcd); +#endif + dwc_otg_pcd_remove(otg_dev->pcd); + free_wrapper(gadget_wrapper); + otg_dev->pcd = 0; +} + +/** + * This function registers a gadget driver with the PCD. + * + * When a driver is successfully registered, it will receive control + * requests including set_configuration(), which enables non-control + * requests. then usb traffic follows until a disconnect is reported. + * then a host may connect again, or the driver might get unbound. + * + * @param driver The driver being registered + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +#else +int usb_gadget_probe_driver(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) +#endif +{ + int retval; + + DWC_DEBUGPL(DBG_PCD, "registering gadget driver '%s'\n", + driver->driver.name); + + if (!driver || driver->speed == USB_SPEED_UNKNOWN || +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) + !driver->bind || +#else + !bind || +#endif + !driver->unbind || !driver->disconnect || !driver->setup) { + DWC_DEBUGPL(DBG_PCDV, "EINVAL\n"); + return -EINVAL; + } + if (gadget_wrapper == 0) { + DWC_DEBUGPL(DBG_PCDV, "ENODEV\n"); + return -ENODEV; + } + if (gadget_wrapper->driver != 0) { + DWC_DEBUGPL(DBG_PCDV, "EBUSY (%p)\n", gadget_wrapper->driver); + return -EBUSY; + } + + /* hook up the driver */ + gadget_wrapper->driver = driver; + gadget_wrapper->gadget.dev.driver = &driver->driver; + + DWC_DEBUGPL(DBG_PCD, "bind to driver %s\n", driver->driver.name); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) + retval = driver->bind(&gadget_wrapper->gadget); +#else + retval = bind(&gadget_wrapper->gadget); +#endif + if (retval) { + DWC_ERROR("bind to driver %s --> error %d\n", + driver->driver.name, retval); + gadget_wrapper->driver = 0; + gadget_wrapper->gadget.dev.driver = 0; + return retval; + } + DWC_DEBUGPL(DBG_ANY, "registered gadget driver '%s'\n", + driver->driver.name); + return 0; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) +EXPORT_SYMBOL(usb_gadget_register_driver); +#else +EXPORT_SYMBOL(usb_gadget_probe_driver); +#endif + +/** + * This function unregisters a gadget driver + * + * @param driver The driver being unregistered + */ +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + //DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _driver); + + if (gadget_wrapper == 0) { + DWC_DEBUGPL(DBG_ANY, "%s Return(%d): s_pcd==0\n", __func__, + -ENODEV); + return -ENODEV; + } + if (driver == 0 || driver != gadget_wrapper->driver) { + DWC_DEBUGPL(DBG_ANY, "%s Return(%d): driver?\n", __func__, + -EINVAL); + return -EINVAL; + } + + driver->unbind(&gadget_wrapper->gadget); + gadget_wrapper->driver = 0; + + DWC_DEBUGPL(DBG_ANY, "unregistered driver '%s'\n", driver->driver.name); + return 0; +} + +EXPORT_SYMBOL(usb_gadget_unregister_driver); + +#endif /* DWC_HOST_ONLY */ diff --git a/drivers/usb/host/dwc_otg/dwc_otg_regs.h b/drivers/usb/host/dwc_otg/dwc_otg_regs.h new file mode 100644 index 000000000000..e8220ad04784 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_regs.h @@ -0,0 +1,2237 @@ +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_regs.h $ + * $Revision: #76 $ + * $Date: 2009/04/02 $ + * $Change: 1224216 $ + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +#ifndef __DWC_OTG_REGS_H__ +#define __DWC_OTG_REGS_H__ + +#include "dwc_otg_core_if.h" + +/** + * @file + * + * This file contains the data structures for accessing the DWC_otg core registers. + * + * The application interfaces with the HS OTG core by reading from and + * writing to the Control and Status Register (CSR) space through the + * AHB Slave interface. These registers are 32 bits wide, and the + * addresses are 32-bit-block aligned. + * CSRs are classified as follows: + * - Core Global Registers + * - Device Mode Registers + * - Device Global Registers + * - Device Endpoint Specific Registers + * - Host Mode Registers + * - Host Global Registers + * - Host Port CSRs + * - Host Channel Specific Registers + * + * Only the Core Global registers can be accessed in both Device and + * Host modes. When the HS OTG core is operating in one mode, either + * Device or Host, the application must not access registers from the + * other mode. When the core switches from one mode to another, the + * registers in the new mode of operation must be reprogrammed as they + * would be after a power-on reset. + */ + +/****************************************************************************/ +/** DWC_otg Core registers . + * The dwc_otg_core_global_regs structure defines the size + * and relative field offsets for the Core Global registers. + */ +typedef struct dwc_otg_core_global_regs { + /** OTG Control and Status Register. Offset: 000h */ + volatile uint32_t gotgctl; + /** OTG Interrupt Register. Offset: 004h */ + volatile uint32_t gotgint; + /**Core AHB Configuration Register. Offset: 008h */ + volatile uint32_t gahbcfg; + +#define DWC_GLBINTRMASK 0x0001 +#define DWC_DMAENABLE 0x0020 +#define DWC_NPTXEMPTYLVL_EMPTY 0x0080 +#define DWC_NPTXEMPTYLVL_HALFEMPTY 0x0000 +#define DWC_PTXEMPTYLVL_EMPTY 0x0100 +#define DWC_PTXEMPTYLVL_HALFEMPTY 0x0000 + + /**Core USB Configuration Register. Offset: 00Ch */ + volatile uint32_t gusbcfg; + /**Core Reset Register. Offset: 010h */ + volatile uint32_t grstctl; + /**Core Interrupt Register. Offset: 014h */ + volatile uint32_t gintsts; + /**Core Interrupt Mask Register. Offset: 018h */ + volatile uint32_t gintmsk; + /**Receive Status Queue Read Register (Read Only). Offset: 01Ch */ + volatile uint32_t grxstsr; + /**Receive Status Queue Read & POP Register (Read Only). Offset: 020h*/ + volatile uint32_t grxstsp; + /**Receive FIFO Size Register. Offset: 024h */ + volatile uint32_t grxfsiz; + /**Non Periodic Transmit FIFO Size Register. Offset: 028h */ + volatile uint32_t gnptxfsiz; + /**Non Periodic Transmit FIFO/Queue Status Register (Read + * Only). Offset: 02Ch */ + volatile uint32_t gnptxsts; + /**I2C Access Register. Offset: 030h */ + volatile uint32_t gi2cctl; + /**PHY Vendor Control Register. Offset: 034h */ + volatile uint32_t gpvndctl; + /**General Purpose Input/Output Register. Offset: 038h */ + volatile uint32_t ggpio; + /**User ID Register. Offset: 03Ch */ + volatile uint32_t guid; + /**Synopsys ID Register (Read Only). Offset: 040h */ + volatile uint32_t gsnpsid; + /**User HW Config1 Register (Read Only). Offset: 044h */ + volatile uint32_t ghwcfg1; + /**User HW Config2 Register (Read Only). Offset: 048h */ + volatile uint32_t ghwcfg2; +#define DWC_SLAVE_ONLY_ARCH 0 +#define DWC_EXT_DMA_ARCH 1 +#define DWC_INT_DMA_ARCH 2 + +#define DWC_MODE_HNP_SRP_CAPABLE 0 +#define DWC_MODE_SRP_ONLY_CAPABLE 1 +#define DWC_MODE_NO_HNP_SRP_CAPABLE 2 +#define DWC_MODE_SRP_CAPABLE_DEVICE 3 +#define DWC_MODE_NO_SRP_CAPABLE_DEVICE 4 +#define DWC_MODE_SRP_CAPABLE_HOST 5 +#define DWC_MODE_NO_SRP_CAPABLE_HOST 6 + + /**User HW Config3 Register (Read Only). Offset: 04Ch */ + volatile uint32_t ghwcfg3; + /**User HW Config4 Register (Read Only). Offset: 050h*/ + volatile uint32_t ghwcfg4; + /** Core LPM Configuration register */ + volatile uint32_t glpmcfg; + /** Reserved Offset: 058h-0FFh */ + volatile uint32_t reserved[42]; + /** Host Periodic Transmit FIFO Size Register. Offset: 100h */ + volatile uint32_t hptxfsiz; + /** Device Periodic Transmit FIFO#n Register if dedicated fifos are disabled, + otherwise Device Transmit FIFO#n Register. + * Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15). */ + volatile uint32_t dptxfsiz_dieptxf[15]; +} dwc_otg_core_global_regs_t; + +/** + * This union represents the bit fields of the Core OTG Control + * and Status Register (GOTGCTL). Set the bits using the bit + * fields then write the d32 value to the register. + */ +typedef union gotgctl_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned sesreqscs:1; + unsigned sesreq:1; + unsigned reserved2_7:6; + unsigned hstnegscs:1; + unsigned hnpreq:1; + unsigned hstsethnpen:1; + unsigned devhnpen:1; + unsigned reserved12_15:4; + unsigned conidsts:1; + unsigned reserved17:1; + unsigned asesvld:1; + unsigned bsesvld:1; + unsigned currmod:1; + unsigned reserved21_31:11; + } b; +} gotgctl_data_t; + +/** + * This union represents the bit fields of the Core OTG Interrupt Register + * (GOTGINT). Set/clear the bits using the bit fields then write the d32 + * value to the register. + */ +typedef union gotgint_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** Current Mode */ + unsigned reserved0_1:2; + + /** Session End Detected */ + unsigned sesenddet:1; + + unsigned reserved3_7:5; + + /** Session Request Success Status Change */ + unsigned sesreqsucstschng:1; + /** Host Negotiation Success Status Change */ + unsigned hstnegsucstschng:1; + + unsigned reserver10_16:7; + + /** Host Negotiation Detected */ + unsigned hstnegdet:1; + /** A-Device Timeout Change */ + unsigned adevtoutchng:1; + /** Debounce Done */ + unsigned debdone:1; + + unsigned reserved31_20:12; + + } b; +} gotgint_data_t; + +/** + * This union represents the bit fields of the Core AHB Configuration + * Register (GAHBCFG). Set/clear the bits using the bit fields then + * write the d32 value to the register. + */ +typedef union gahbcfg_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned glblintrmsk:1; +#define DWC_GAHBCFG_GLBINT_ENABLE 1 + + unsigned hburstlen:4; +#define DWC_GAHBCFG_INT_DMA_BURST_SINGLE 0 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR 1 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR4 3 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR8 5 +#define DWC_GAHBCFG_INT_DMA_BURST_INCR16 7 + + unsigned dmaenable:1; +#define DWC_GAHBCFG_DMAENABLE 1 + unsigned reserved:1; + unsigned nptxfemplvl_txfemplvl:1; + unsigned ptxfemplvl:1; +#define DWC_GAHBCFG_TXFEMPTYLVL_EMPTY 1 +#define DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0 + unsigned reserved9_31:23; + } b; +} gahbcfg_data_t; + +/** + * This union represents the bit fields of the Core USB Configuration + * Register (GUSBCFG). Set the bits using the bit fields then write + * the d32 value to the register. + */ +typedef union gusbcfg_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned toutcal:3; + unsigned phyif:1; + unsigned ulpi_utmi_sel:1; + unsigned fsintf:1; + unsigned physel:1; + unsigned ddrsel:1; + unsigned srpcap:1; + unsigned hnpcap:1; + unsigned usbtrdtim:4; + unsigned nptxfrwnden:1; + unsigned phylpwrclksel:1; + unsigned otgutmifssel:1; + unsigned ulpi_fsls:1; + unsigned ulpi_auto_res:1; + unsigned ulpi_clk_sus_m:1; + unsigned ulpi_ext_vbus_drv:1; + unsigned ulpi_int_vbus_indicator:1; + unsigned term_sel_dl_pulse:1; + unsigned reserved23_25:3; + unsigned ic_usb_cap:1; + unsigned ic_traffic_pull_remove:1; + unsigned tx_end_delay:1; + unsigned reserved29_31:3; + } b; +} gusbcfg_data_t; + +/** + * This union represents the bit fields of the Core LPM Configuration + * Register (GLPMCFG). Set the bits using bit fields then write + * the d32 value to the register. + */ +typedef union glpmctl_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** LPM-Capable (LPMCap) (Device and Host) + * The application uses this bit to control + * the DWC_otg core LPM capabilities. + */ + unsigned lpm_cap_en:1; + /** LPM response programmed by application (AppL1Res) (Device) + * Handshake response to LPM token pre-programmed + * by device application software. + */ + unsigned appl_resp:1; + /** Host Initiated Resume Duration (HIRD) (Device and Host) + * In Host mode this field indicates the value of HIRD + * to be sent in an LPM transaction. + * In Device mode this field is updated with the + * Received LPM Token HIRD bmAttribute + * when an ACK/NYET/STALL response is sent + * to an LPM transaction. + */ + unsigned hird:4; + /** RemoteWakeEnable (bRemoteWake) (Device and Host) + * In Host mode this bit indicates the value of remote + * wake up to be sent in wIndex field of LPM transaction. + * In Device mode this field is updated with the + * Received LPM Token bRemoteWake bmAttribute + * when an ACK/NYET/STALL response is sent + * to an LPM transaction. + */ + unsigned rem_wkup_en:1; + /** Enable utmi_sleep_n (EnblSlpM) (Device and Host) + * The application uses this bit to control + * the utmi_sleep_n assertion to the PHY when in L1 state. + */ + unsigned en_utmi_sleep:1; + /** HIRD Threshold (HIRD_Thres) (Device and Host) + */ + unsigned hird_thres:5; + /** LPM Response (CoreL1Res) (Device and Host) + * In Host mode this bit contains handsake response to + * LPM transaction. + * In Device mode the response of the core to + * LPM transaction received is reflected in these two bits. + - 0x0 : ERROR (No handshake response) + - 0x1 : STALL + - 0x2 : NYET + - 0x3 : ACK + */ + unsigned lpm_resp:2; + /** Port Sleep Status (SlpSts) (Device and Host) + * This bit is set as long as a Sleep condition + * is present on the USB bus. + */ + unsigned prt_sleep_sts:1; + /** Sleep State Resume OK (L1ResumeOK) (Device and Host) + * Indicates that the application or host + * can start resume from Sleep state. + */ + unsigned sleep_state_resumeok:1; + /** LPM channel Index (LPM_Chnl_Indx) (Host) + * The channel number on which the LPM transaction + * has to be applied while sending + * an LPM transaction to the local device. + */ + unsigned lpm_chan_index:4; + /** LPM Retry Count (LPM_Retry_Cnt) (Host) + * Number host retries that would be performed + * if the device response was not valid response. + */ + unsigned retry_count:3; + /** Send LPM Transaction (SndLPM) (Host) + * When set by application software, + * an LPM transaction containing two tokens + * is sent. + */ + unsigned send_lpm:1; + /** LPM Retry status (LPM_RetryCnt_Sts) (Host) + * Number of LPM Host Retries still remaining + * to be transmitted for the current LPM sequence + */ + unsigned retry_count_sts:3; + unsigned reserved28_29:2; + /** In host mode once this bit is set, the host + * configures to drive the HSIC Idle state on the bus. + * It then waits for the device to initiate the Connect sequence. + * In device mode once this bit is set, the device waits for + * the HSIC Idle line state on the bus. Upon receving the Idle + * line state, it initiates the HSIC Connect sequence. + */ + unsigned hsic_connect:1; + /** This bit overrides and functionally inverts + * the if_select_hsic input port signal. + */ + unsigned inv_sel_hsic:1; + } b; +} glpmcfg_data_t; + +/** + * This union represents the bit fields of the Core Reset Register + * (GRSTCTL). Set/clear the bits using the bit fields then write the + * d32 value to the register. + */ +typedef union grstctl_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** Core Soft Reset (CSftRst) (Device and Host) + * + * The application can flush the control logic in the + * entire core using this bit. This bit resets the + * pipelines in the AHB Clock domain as well as the + * PHY Clock domain. + * + * The state machines are reset to an IDLE state, the + * control bits in the CSRs are cleared, all the + * transmit FIFOs and the receive FIFO are flushed. + * + * The status mask bits that control the generation of + * the interrupt, are cleared, to clear the + * interrupt. The interrupt status bits are not + * cleared, so the application can get the status of + * any events that occurred in the core after it has + * set this bit. + * + * Any transactions on the AHB are terminated as soon + * as possible following the protocol. Any + * transactions on the USB are terminated immediately. + * + * The configuration settings in the CSRs are + * unchanged, so the software doesn't have to + * reprogram these registers (Device + * Configuration/Host Configuration/Core System + * Configuration/Core PHY Configuration). + * + * The application can write to this bit, any time it + * wants to reset the core. This is a self clearing + * bit and the core clears this bit after all the + * necessary logic is reset in the core, which may + * take several clocks, depending on the current state + * of the core. + */ + unsigned csftrst:1; + /** Hclk Soft Reset + * + * The application uses this bit to reset the control logic in + * the AHB clock domain. Only AHB clock domain pipelines are + * reset. + */ + unsigned hsftrst:1; + /** Host Frame Counter Reset (Host Only)
+ * + * The application can reset the (micro)frame number + * counter inside the core, using this bit. When the + * (micro)frame counter is reset, the subsequent SOF + * sent out by the core, will have a (micro)frame + * number of 0. + */ + unsigned hstfrm:1; + /** In Token Sequence Learning Queue Flush + * (INTknQFlsh) (Device Only) + */ + unsigned intknqflsh:1; + /** RxFIFO Flush (RxFFlsh) (Device and Host) + * + * The application can flush the entire Receive FIFO + * using this bit.

The application must first + * ensure that the core is not in the middle of a + * transaction.

The application should write into + * this bit, only after making sure that neither the + * DMA engine is reading from the RxFIFO nor the MAC + * is writing the data in to the FIFO.

The + * application should wait until the bit is cleared + * before performing any other operations. This bit + * will takes 8 clocks (slowest of PHY or AHB clock) + * to clear. + */ + unsigned rxfflsh:1; + /** TxFIFO Flush (TxFFlsh) (Device and Host). + * + * This bit is used to selectively flush a single or + * all transmit FIFOs. The application must first + * ensure that the core is not in the middle of a + * transaction.

The application should write into + * this bit, only after making sure that neither the + * DMA engine is writing into the TxFIFO nor the MAC + * is reading the data out of the FIFO.

The + * application should wait until the core clears this + * bit, before performing any operations. This bit + * will takes 8 clocks (slowest of PHY or AHB clock) + * to clear. + */ + unsigned txfflsh:1; + + /** TxFIFO Number (TxFNum) (Device and Host). + * + * This is the FIFO number which needs to be flushed, + * using the TxFIFO Flush bit. This field should not + * be changed until the TxFIFO Flush bit is cleared by + * the core. + * - 0x0 : Non Periodic TxFIFO Flush + * - 0x1 : Periodic TxFIFO #1 Flush in device mode + * or Periodic TxFIFO in host mode + * - 0x2 : Periodic TxFIFO #2 Flush in device mode. + * - ... + * - 0xF : Periodic TxFIFO #15 Flush in device mode + * - 0x10: Flush all the Transmit NonPeriodic and + * Transmit Periodic FIFOs in the core + */ + unsigned txfnum:5; + /** Reserved */ + unsigned reserved11_29:19; + /** DMA Request Signal. Indicated DMA request is in + * probress. Used for debug purpose. */ + unsigned dmareq:1; + /** AHB Master Idle. Indicates the AHB Master State + * Machine is in IDLE condition. */ + unsigned ahbidle:1; + } b; +} grstctl_t; + +/** + * This union represents the bit fields of the Core Interrupt Mask + * Register (GINTMSK). Set/clear the bits using the bit fields then + * write the d32 value to the register. + */ +typedef union gintmsk_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned reserved0:1; + unsigned modemismatch:1; + unsigned otgintr:1; + unsigned sofintr:1; + unsigned rxstsqlvl:1; + unsigned nptxfempty:1; + unsigned ginnakeff:1; + unsigned goutnakeff:1; + unsigned reserved8:1; + unsigned i2cintr:1; + unsigned erlysuspend:1; + unsigned usbsuspend:1; + unsigned usbreset:1; + unsigned enumdone:1; + unsigned isooutdrop:1; + unsigned eopframe:1; + unsigned reserved16:1; + unsigned epmismatch:1; + unsigned inepintr:1; + unsigned outepintr:1; + unsigned incomplisoin:1; + unsigned incomplisoout:1; + unsigned reserved22_23:2; + unsigned portintr:1; + unsigned hcintr:1; + unsigned ptxfempty:1; + unsigned lpmtranrcvd:1; + unsigned conidstschng:1; + unsigned disconnect:1; + unsigned sessreqintr:1; + unsigned wkupintr:1; + } b; +} gintmsk_data_t; +/** + * This union represents the bit fields of the Core Interrupt Register + * (GINTSTS). Set/clear the bits using the bit fields then write the + * d32 value to the register. + */ +typedef union gintsts_data { + /** raw register data */ + uint32_t d32; +#define DWC_SOF_INTR_MASK 0x0008 + /** register bits */ + struct { +#define DWC_HOST_MODE 1 + unsigned curmode:1; + unsigned modemismatch:1; + unsigned otgintr:1; + unsigned sofintr:1; + unsigned rxstsqlvl:1; + unsigned nptxfempty:1; + unsigned ginnakeff:1; + unsigned goutnakeff:1; + unsigned reserved8:1; + unsigned i2cintr:1; + unsigned erlysuspend:1; + unsigned usbsuspend:1; + unsigned usbreset:1; + unsigned enumdone:1; + unsigned isooutdrop:1; + unsigned eopframe:1; + unsigned intokenrx:1; + unsigned epmismatch:1; + unsigned inepint:1; + unsigned outepintr:1; + unsigned incomplisoin:1; + unsigned incomplisoout:1; + unsigned reserved22_23:2; + unsigned portintr:1; + unsigned hcintr:1; + unsigned ptxfempty:1; + unsigned lpmtranrcvd:1; + unsigned conidstschng:1; + unsigned disconnect:1; + unsigned sessreqintr:1; + unsigned wkupintr:1; + } b; +} gintsts_data_t; + +/** + * This union represents the bit fields in the Device Receive Status Read and + * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the d32 + * element then read out the bits using the bit elements. + */ +typedef union device_grxsts_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned epnum:4; + unsigned bcnt:11; + unsigned dpid:2; + +#define DWC_STS_DATA_UPDT 0x2 // OUT Data Packet +#define DWC_STS_XFER_COMP 0x3 // OUT Data Transfer Complete + +#define DWC_DSTS_GOUT_NAK 0x1 // Global OUT NAK +#define DWC_DSTS_SETUP_COMP 0x4 // Setup Phase Complete +#define DWC_DSTS_SETUP_UPDT 0x6 // SETUP Packet + unsigned pktsts:4; + unsigned fn:4; + unsigned reserved:7; + } b; +} device_grxsts_data_t; + +/** + * This union represents the bit fields in the Host Receive Status Read and + * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the d32 + * element then read out the bits using the bit elements. + */ +typedef union host_grxsts_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned chnum:4; + unsigned bcnt:11; + unsigned dpid:2; + + unsigned pktsts:4; +#define DWC_GRXSTS_PKTSTS_IN 0x2 +#define DWC_GRXSTS_PKTSTS_IN_XFER_COMP 0x3 +#define DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR 0x5 +#define DWC_GRXSTS_PKTSTS_CH_HALTED 0x7 + + unsigned reserved:11; + } b; +} host_grxsts_data_t; + +/** + * This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ, + * GNPTXFSIZ, DPTXFSIZn, DIEPTXFn). Read the register into the d32 element then + * read out the bits using the bit elements. + */ +typedef union fifosize_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned startaddr:16; + unsigned depth:16; + } b; +} fifosize_data_t; + +/** + * This union represents the bit fields in the Non-Periodic Transmit + * FIFO/Queue Status Register (GNPTXSTS). Read the register into the + * d32 element then read out the bits using the bit + * elements. + */ +typedef union gnptxsts_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned nptxfspcavail:16; + unsigned nptxqspcavail:8; + /** Top of the Non-Periodic Transmit Request Queue + * - bit 24 - Terminate (Last entry for the selected + * channel/EP) + * - bits 26:25 - Token Type + * - 2'b00 - IN/OUT + * - 2'b01 - Zero Length OUT + * - 2'b10 - PING/Complete Split + * - 2'b11 - Channel Halt + * - bits 30:27 - Channel/EP Number + */ + unsigned nptxqtop_terminate:1; + unsigned nptxqtop_token:2; + unsigned nptxqtop_chnep:4; + unsigned reserved:1; + } b; +} gnptxsts_data_t; + +/** + * This union represents the bit fields in the Transmit + * FIFO Status Register (DTXFSTS). Read the register into the + * d32 element then read out the bits using the bit + * elements. + */ +typedef union dtxfsts_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned txfspcavail:16; + unsigned reserved:16; + } b; +} dtxfsts_data_t; + +/** + * This union represents the bit fields in the I2C Control Register + * (I2CCTL). Read the register into the d32 element then read out the + * bits using the bit elements. + */ +typedef union gi2cctl_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned rwdata:8; + unsigned regaddr:8; + unsigned addr:7; + unsigned i2cen:1; + unsigned ack:1; + unsigned i2csuspctl:1; + unsigned i2cdevaddr:2; + unsigned reserved:2; + unsigned rw:1; + unsigned bsydne:1; + } b; +} gi2cctl_data_t; + +/** + * This union represents the bit fields in the User HW Config1 + * Register. Read the register into the d32 element then read + * out the bits using the bit elements. + */ +typedef union hwcfg1_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned ep_dir0:2; + unsigned ep_dir1:2; + unsigned ep_dir2:2; + unsigned ep_dir3:2; + unsigned ep_dir4:2; + unsigned ep_dir5:2; + unsigned ep_dir6:2; + unsigned ep_dir7:2; + unsigned ep_dir8:2; + unsigned ep_dir9:2; + unsigned ep_dir10:2; + unsigned ep_dir11:2; + unsigned ep_dir12:2; + unsigned ep_dir13:2; + unsigned ep_dir14:2; + unsigned ep_dir15:2; + } b; +} hwcfg1_data_t; + +/** + * This union represents the bit fields in the User HW Config2 + * Register. Read the register into the d32 element then read + * out the bits using the bit elements. + */ +typedef union hwcfg2_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /* GHWCFG2 */ + unsigned op_mode:3; +#define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0 +#define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1 +#define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2 +#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3 +#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4 +#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5 +#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6 + + unsigned architecture:2; + unsigned point2point:1; + unsigned hs_phy_type:2; +#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0 +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1 +#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2 +#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3 + + unsigned fs_phy_type:2; + unsigned num_dev_ep:4; + unsigned num_host_chan:4; + unsigned perio_ep_supported:1; + unsigned dynamic_fifo:1; + unsigned multi_proc_int:1; + unsigned reserved21:1; + unsigned nonperio_tx_q_depth:2; + unsigned host_perio_tx_q_depth:2; + unsigned dev_token_q_depth:5; + unsigned reserved31:1; + } b; +} hwcfg2_data_t; + +/** + * This union represents the bit fields in the User HW Config3 + * Register. Read the register into the d32 element then read + * out the bits using the bit elements. + */ +typedef union hwcfg3_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /* GHWCFG3 */ + unsigned xfer_size_cntr_width:4; + unsigned packet_size_cntr_width:3; + unsigned otg_func:1; + unsigned i2c:1; + unsigned vendor_ctrl_if:1; + unsigned optional_features:1; + unsigned synch_reset_type:1; + unsigned otg_enable_ic_usb:1; + unsigned otg_enable_hsic:1; + unsigned reserved14:1; + unsigned otg_lpm_en:1; + unsigned dfifo_depth:16; + } b; +} hwcfg3_data_t; + +/** + * This union represents the bit fields in the User HW Config4 + * Register. Read the register into the d32 element then read + * out the bits using the bit elements. + */ +typedef union hwcfg4_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned num_dev_perio_in_ep:4; + unsigned power_optimiz:1; + unsigned min_ahb_freq:9; + unsigned utmi_phy_data_width:2; + unsigned num_dev_mode_ctrl_ep:4; + unsigned iddig_filt_en:1; + unsigned vbus_valid_filt_en:1; + unsigned a_valid_filt_en:1; + unsigned b_valid_filt_en:1; + unsigned session_end_filt_en:1; + unsigned ded_fifo_en:1; + unsigned num_in_eps:4; + unsigned desc_dma:1; + unsigned desc_dma_dyn:1; + } b; +} hwcfg4_data_t; + +//////////////////////////////////////////// +// Device Registers +/** + * Device Global Registers. Offsets 800h-BFFh + * + * The following structures define the size and relative field offsets + * for the Device Mode Registers. + * + * These registers are visible only in Device mode and must not be + * accessed in Host mode, as the results are unknown. + */ +typedef struct dwc_otg_dev_global_regs { + /** Device Configuration Register. Offset 800h */ + volatile uint32_t dcfg; + /** Device Control Register. Offset: 804h */ + volatile uint32_t dctl; + /** Device Status Register (Read Only). Offset: 808h */ + volatile uint32_t dsts; + /** Reserved. Offset: 80Ch */ + uint32_t unused; + /** Device IN Endpoint Common Interrupt Mask + * Register. Offset: 810h */ + volatile uint32_t diepmsk; + /** Device OUT Endpoint Common Interrupt Mask + * Register. Offset: 814h */ + volatile uint32_t doepmsk; + /** Device All Endpoints Interrupt Register. Offset: 818h */ + volatile uint32_t daint; + /** Device All Endpoints Interrupt Mask Register. Offset: + * 81Ch */ + volatile uint32_t daintmsk; + /** Device IN Token Queue Read Register-1 (Read Only). + * Offset: 820h */ + volatile uint32_t dtknqr1; + /** Device IN Token Queue Read Register-2 (Read Only). + * Offset: 824h */ + volatile uint32_t dtknqr2; + /** Device VBUS discharge Register. Offset: 828h */ + volatile uint32_t dvbusdis; + /** Device VBUS Pulse Register. Offset: 82Ch */ + volatile uint32_t dvbuspulse; + /** Device IN Token Queue Read Register-3 (Read Only). / + * Device Thresholding control register (Read/Write) + * Offset: 830h */ + volatile uint32_t dtknqr3_dthrctl; + /** Device IN Token Queue Read Register-4 (Read Only). / + * Device IN EPs empty Inr. Mask Register (Read/Write) + * Offset: 834h */ + volatile uint32_t dtknqr4_fifoemptymsk; + /** Device Each Endpoint Interrupt Register (Read Only). / + * Offset: 838h */ + volatile uint32_t deachint; + /** Device Each Endpoint Interrupt mask Register (Read/Write). / + * Offset: 83Ch */ + volatile uint32_t deachintmsk; + /** Device Each In Endpoint Interrupt mask Register (Read/Write). / + * Offset: 840h */ + volatile uint32_t diepeachintmsk[MAX_EPS_CHANNELS]; + /** Device Each Out Endpoint Interrupt mask Register (Read/Write). / + * Offset: 880h */ + volatile uint32_t doepeachintmsk[MAX_EPS_CHANNELS]; +} dwc_otg_device_global_regs_t; + +/** + * This union represents the bit fields in the Device Configuration + * Register. Read the register into the d32 member then + * set/clear the bits using the bit elements. Write the + * d32 member to the dcfg register. + */ +typedef union dcfg_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** Device Speed */ + unsigned devspd:2; + /** Non Zero Length Status OUT Handshake */ + unsigned nzstsouthshk:1; +#define DWC_DCFG_SEND_STALL 1 + + unsigned reserved3:1; + /** Device Addresses */ + unsigned devaddr:7; + /** Periodic Frame Interval */ + unsigned perfrint:2; +#define DWC_DCFG_FRAME_INTERVAL_80 0 +#define DWC_DCFG_FRAME_INTERVAL_85 1 +#define DWC_DCFG_FRAME_INTERVAL_90 2 +#define DWC_DCFG_FRAME_INTERVAL_95 3 + + unsigned reserved13_17:5; + /** In Endpoint Mis-match count */ + unsigned epmscnt:5; + /** Enable Descriptor DMA in Device mode */ + unsigned descdma:1; + } b; +} dcfg_data_t; + +/** + * This union represents the bit fields in the Device Control + * Register. Read the register into the d32 member then + * set/clear the bits using the bit elements. + */ +typedef union dctl_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** Remote Wakeup */ + unsigned rmtwkupsig:1; + /** Soft Disconnect */ + unsigned sftdiscon:1; + /** Global Non-Periodic IN NAK Status */ + unsigned gnpinnaksts:1; + /** Global OUT NAK Status */ + unsigned goutnaksts:1; + /** Test Control */ + unsigned tstctl:3; + /** Set Global Non-Periodic IN NAK */ + unsigned sgnpinnak:1; + /** Clear Global Non-Periodic IN NAK */ + unsigned cgnpinnak:1; + /** Set Global OUT NAK */ + unsigned sgoutnak:1; + /** Clear Global OUT NAK */ + unsigned cgoutnak:1; + + /** Power-On Programming Done */ + unsigned pwronprgdone:1; + /** Global Continue on BNA */ + unsigned gcontbna:1; + /** Global Multi Count */ + unsigned gmc:2; + /** Ignore Frame Number for ISOC EPs */ + unsigned ifrmnum:1; + /** NAK on Babble */ + unsigned nakonbble:1; + + unsigned reserved17_31:15; + } b; +} dctl_data_t; + +/** + * This union represents the bit fields in the Device Status + * Register. Read the register into the d32 member then + * set/clear the bits using the bit elements. + */ +typedef union dsts_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** Suspend Status */ + unsigned suspsts:1; + /** Enumerated Speed */ + unsigned enumspd:2; +#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0 +#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1 +#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ 2 +#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ 3 + /** Erratic Error */ + unsigned errticerr:1; + unsigned reserved4_7:4; + /** Frame or Microframe Number of the received SOF */ + unsigned soffn:14; + unsigned reserved22_31:10; + } b; +} dsts_data_t; + +/** + * This union represents the bit fields in the Device IN EP Interrupt + * Register and the Device IN EP Common Mask Register. + * + * - Read the register into the d32 member then set/clear the + * bits using the bit elements. + */ +typedef union diepint_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** Transfer complete mask */ + unsigned xfercompl:1; + /** Endpoint disable mask */ + unsigned epdisabled:1; + /** AHB Error mask */ + unsigned ahberr:1; + /** TimeOUT Handshake mask (non-ISOC EPs) */ + unsigned timeout:1; + /** IN Token received with TxF Empty mask */ + unsigned intktxfemp:1; + /** IN Token Received with EP mismatch mask */ + unsigned intknepmis:1; + /** IN Endpoint HAK Effective mask */ + unsigned inepnakeff:1; + /** IN Endpoint HAK Effective mask */ + unsigned emptyintr:1; + + unsigned txfifoundrn:1; + + /** BNA Interrupt mask */ + unsigned bna:1; + + unsigned reserved10_12:3; + /** BNA Interrupt mask */ + unsigned nak:1; + + unsigned reserved14_31:18; + } b; +} diepint_data_t; + +/** + * This union represents the bit fields in the Device IN EP + * Common/Dedicated Interrupt Mask Register. + */ +typedef union diepint_data diepmsk_data_t; + +/** + * This union represents the bit fields in the Device OUT EP Interrupt + * Registerand Device OUT EP Common Interrupt Mask Register. + * + * - Read the register into the d32 member then set/clear the + * bits using the bit elements. + */ +typedef union doepint_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** Transfer complete */ + unsigned xfercompl:1; + /** Endpoint disable */ + unsigned epdisabled:1; + /** AHB Error */ + unsigned ahberr:1; + /** Setup Phase Done (contorl EPs) */ + unsigned setup:1; + /** OUT Token Received when Endpoint Disabled */ + unsigned outtknepdis:1; + + unsigned stsphsercvd:1; + /** Back-to-Back SETUP Packets Received */ + unsigned back2backsetup:1; + + unsigned reserved7:1; + /** OUT packet Error */ + unsigned outpkterr:1; + /** BNA Interrupt */ + unsigned bna:1; + + unsigned reserved10:1; + /** Packet Drop Status */ + unsigned pktdrpsts:1; + /** Babble Interrupt */ + unsigned babble:1; + /** NAK Interrupt */ + unsigned nak:1; + /** NYET Interrupt */ + unsigned nyet:1; + + unsigned reserved15_31:17; + } b; +} doepint_data_t; + +/** + * This union represents the bit fields in the Device OUT EP + * Common/Dedicated Interrupt Mask Register. + */ +typedef union doepint_data doepmsk_data_t; + +/** + * This union represents the bit fields in the Device All EP Interrupt + * and Mask Registers. + * - Read the register into the d32 member then set/clear the + * bits using the bit elements. + */ +typedef union daint_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** IN Endpoint bits */ + unsigned in:16; + /** OUT Endpoint bits */ + unsigned out:16; + } ep; + struct { + /** IN Endpoint bits */ + unsigned inep0:1; + unsigned inep1:1; + unsigned inep2:1; + unsigned inep3:1; + unsigned inep4:1; + unsigned inep5:1; + unsigned inep6:1; + unsigned inep7:1; + unsigned inep8:1; + unsigned inep9:1; + unsigned inep10:1; + unsigned inep11:1; + unsigned inep12:1; + unsigned inep13:1; + unsigned inep14:1; + unsigned inep15:1; + /** OUT Endpoint bits */ + unsigned outep0:1; + unsigned outep1:1; + unsigned outep2:1; + unsigned outep3:1; + unsigned outep4:1; + unsigned outep5:1; + unsigned outep6:1; + unsigned outep7:1; + unsigned outep8:1; + unsigned outep9:1; + unsigned outep10:1; + unsigned outep11:1; + unsigned outep12:1; + unsigned outep13:1; + unsigned outep14:1; + unsigned outep15:1; + } b; +} daint_data_t; + +/** + * This union represents the bit fields in the Device IN Token Queue + * Read Registers. + * - Read the register into the d32 member. + * - READ-ONLY Register + */ +typedef union dtknq1_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** In Token Queue Write Pointer */ + unsigned intknwptr:5; + /** Reserved */ + unsigned reserved05_06:2; + /** write pointer has wrapped. */ + unsigned wrap_bit:1; + /** EP Numbers of IN Tokens 0 ... 4 */ + unsigned epnums0_5:24; + } b; +} dtknq1_data_t; + +/** + * This union represents Threshold control Register + * - Read and write the register into the d32 member. + * - READ-WRITABLE Register + */ +typedef union dthrctl_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** non ISO Tx Thr. Enable */ + unsigned non_iso_thr_en:1; + /** ISO Tx Thr. Enable */ + unsigned iso_thr_en:1; + /** Tx Thr. Length */ + unsigned tx_thr_len:9; + /** AHB Threshold ratio */ + unsigned ahb_thr_ratio:2; + /** Reserved */ + unsigned reserved13_15:3; + /** Rx Thr. Enable */ + unsigned rx_thr_en:1; + /** Rx Thr. Length */ + unsigned rx_thr_len:9; + /** Reserved */ + unsigned reserved26_31:6; + } b; +} dthrctl_data_t; + +/** + * Device Logical IN Endpoint-Specific Registers. Offsets + * 900h-AFCh + * + * There will be one set of endpoint registers per logical endpoint + * implemented. + * + * These registers are visible only in Device mode and must not be + * accessed in Host mode, as the results are unknown. + */ +typedef struct dwc_otg_dev_in_ep_regs { + /** Device IN Endpoint Control Register. Offset:900h + + * (ep_num * 20h) + 00h */ + volatile uint32_t diepctl; + /** Reserved. Offset:900h + (ep_num * 20h) + 04h */ + uint32_t reserved04; + /** Device IN Endpoint Interrupt Register. Offset:900h + + * (ep_num * 20h) + 08h */ + volatile uint32_t diepint; + /** Reserved. Offset:900h + (ep_num * 20h) + 0Ch */ + uint32_t reserved0C; + /** Device IN Endpoint Transfer Size + * Register. Offset:900h + (ep_num * 20h) + 10h */ + volatile uint32_t dieptsiz; + /** Device IN Endpoint DMA Address Register. Offset:900h + + * (ep_num * 20h) + 14h */ + volatile uint32_t diepdma; + /** Device IN Endpoint Transmit FIFO Status Register. Offset:900h + + * (ep_num * 20h) + 18h */ + volatile uint32_t dtxfsts; + /** Device IN Endpoint DMA Buffer Register. Offset:900h + + * (ep_num * 20h) + 1Ch */ + volatile uint32_t diepdmab; +} dwc_otg_dev_in_ep_regs_t; + +/** + * Device Logical OUT Endpoint-Specific Registers. Offsets: + * B00h-CFCh + * + * There will be one set of endpoint registers per logical endpoint + * implemented. + * + * These registers are visible only in Device mode and must not be + * accessed in Host mode, as the results are unknown. + */ +typedef struct dwc_otg_dev_out_ep_regs { + /** Device OUT Endpoint Control Register. Offset:B00h + + * (ep_num * 20h) + 00h */ + volatile uint32_t doepctl; + /** Device OUT Endpoint Frame number Register. Offset: + * B00h + (ep_num * 20h) + 04h */ + volatile uint32_t doepfn; + /** Device OUT Endpoint Interrupt Register. Offset:B00h + + * (ep_num * 20h) + 08h */ + volatile uint32_t doepint; + /** Reserved. Offset:B00h + (ep_num * 20h) + 0Ch */ + uint32_t reserved0C; + /** Device OUT Endpoint Transfer Size Register. Offset: + * B00h + (ep_num * 20h) + 10h */ + volatile uint32_t doeptsiz; + /** Device OUT Endpoint DMA Address Register. Offset:B00h + * + (ep_num * 20h) + 14h */ + volatile uint32_t doepdma; + /** Reserved. Offset:B00h + * (ep_num * 20h) + 18h */ + uint32_t unused; + /** Device OUT Endpoint DMA Buffer Register. Offset:B00h + * + (ep_num * 20h) + 1Ch */ + uint32_t doepdmab; +} dwc_otg_dev_out_ep_regs_t; + +/** + * This union represents the bit fields in the Device EP Control + * Register. Read the register into the d32 member then + * set/clear the bits using the bit elements. + */ +typedef union depctl_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** Maximum Packet Size + * IN/OUT EPn + * IN/OUT EP0 - 2 bits + * 2'b00: 64 Bytes + * 2'b01: 32 + * 2'b10: 16 + * 2'b11: 8 */ + unsigned mps:11; +#define DWC_DEP0CTL_MPS_64 0 +#define DWC_DEP0CTL_MPS_32 1 +#define DWC_DEP0CTL_MPS_16 2 +#define DWC_DEP0CTL_MPS_8 3 + + /** Next Endpoint + * IN EPn/IN EP0 + * OUT EPn/OUT EP0 - reserved */ + unsigned nextep:4; + + /** USB Active Endpoint */ + unsigned usbactep:1; + + /** Endpoint DPID (INTR/Bulk IN and OUT endpoints) + * This field contains the PID of the packet going to + * be received or transmitted on this endpoint. The + * application should program the PID of the first + * packet going to be received or transmitted on this + * endpoint , after the endpoint is + * activated. Application use the SetD1PID and + * SetD0PID fields of this register to program either + * D0 or D1 PID. + * + * The encoding for this field is + * - 0: D0 + * - 1: D1 + */ + unsigned dpid:1; + + /** NAK Status */ + unsigned naksts:1; + + /** Endpoint Type + * 2'b00: Control + * 2'b01: Isochronous + * 2'b10: Bulk + * 2'b11: Interrupt */ + unsigned eptype:2; + + /** Snoop Mode + * OUT EPn/OUT EP0 + * IN EPn/IN EP0 - reserved */ + unsigned snp:1; + + /** Stall Handshake */ + unsigned stall:1; + + /** Tx Fifo Number + * IN EPn/IN EP0 + * OUT EPn/OUT EP0 - reserved */ + unsigned txfnum:4; + + /** Clear NAK */ + unsigned cnak:1; + /** Set NAK */ + unsigned snak:1; + /** Set DATA0 PID (INTR/Bulk IN and OUT endpoints) + * Writing to this field sets the Endpoint DPID (DPID) + * field in this register to DATA0. Set Even + * (micro)frame (SetEvenFr) (ISO IN and OUT Endpoints) + * Writing to this field sets the Even/Odd + * (micro)frame (EO_FrNum) field to even (micro) + * frame. + */ + unsigned setd0pid:1; + /** Set DATA1 PID (INTR/Bulk IN and OUT endpoints) + * Writing to this field sets the Endpoint DPID (DPID) + * field in this register to DATA1 Set Odd + * (micro)frame (SetOddFr) (ISO IN and OUT Endpoints) + * Writing to this field sets the Even/Odd + * (micro)frame (EO_FrNum) field to odd (micro) frame. + */ + unsigned setd1pid:1; + + /** Endpoint Disable */ + unsigned epdis:1; + /** Endpoint Enable */ + unsigned epena:1; + } b; +} depctl_data_t; + +/** + * This union represents the bit fields in the Device EP Transfer + * Size Register. Read the register into the d32 member then + * set/clear the bits using the bit elements. + */ +typedef union deptsiz_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** Transfer size */ + unsigned xfersize:19; + /** Packet Count */ + unsigned pktcnt:10; + /** Multi Count - Periodic IN endpoints */ + unsigned mc:2; + unsigned reserved:1; + } b; +} deptsiz_data_t; + +/** + * This union represents the bit fields in the Device EP 0 Transfer + * Size Register. Read the register into the d32 member then + * set/clear the bits using the bit elements. + */ +typedef union deptsiz0_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + /** Transfer size */ + unsigned xfersize:7; + /** Reserved */ + unsigned reserved7_18:12; + /** Packet Count */ + unsigned pktcnt:1; + /** Reserved */ + unsigned reserved20_28:9; + /**Setup Packet Count (DOEPTSIZ0 Only) */ + unsigned supcnt:2; + unsigned reserved31; + } b; +} deptsiz0_data_t; + +///////////////////////////////////////////////// +// DMA Descriptor Specific Structures +// + +/** Buffer status definitions */ + +#define BS_HOST_READY 0x0 +#define BS_DMA_BUSY 0x1 +#define BS_DMA_DONE 0x2 +#define BS_HOST_BUSY 0x3 + +/** Receive/Transmit status definitions */ + +#define RTS_SUCCESS 0x0 +#define RTS_BUFFLUSH 0x1 +#define RTS_RESERVED 0x2 +#define RTS_BUFERR 0x3 + +/** + * This union represents the bit fields in the DMA Descriptor + * status quadlet. Read the quadlet into the d32 member then + * set/clear the bits using the bit, b_iso_out and + * b_iso_in elements. + */ +typedef union dev_dma_desc_sts { + /** raw register data */ + uint32_t d32; + /** quadlet bits */ + struct { + /** Received number of bytes */ + unsigned bytes:16; + + unsigned reserved16_22:7; + /** Multiple Transfer - only for OUT EPs */ + unsigned mtrf:1; + /** Setup Packet received - only for OUT EPs */ + unsigned sr:1; + /** Interrupt On Complete */ + unsigned ioc:1; + /** Short Packet */ + unsigned sp:1; + /** Last */ + unsigned l:1; + /** Receive Status */ + unsigned sts:2; + /** Buffer Status */ + unsigned bs:2; + } b; + +#ifdef DWC_EN_ISOC + /** iso out quadlet bits */ + struct { + /** Received number of bytes */ + unsigned rxbytes:11; + + unsigned reserved11:1; + /** Frame Number */ + unsigned framenum:11; + /** Received ISO Data PID */ + unsigned pid:2; + /** Interrupt On Complete */ + unsigned ioc:1; + /** Short Packet */ + unsigned sp:1; + /** Last */ + unsigned l:1; + /** Receive Status */ + unsigned rxsts:2; + /** Buffer Status */ + unsigned bs:2; + } b_iso_out; + + /** iso in quadlet bits */ + struct { + /** Transmited number of bytes */ + unsigned txbytes:12; + /** Frame Number */ + unsigned framenum:11; + /** Transmited ISO Data PID */ + unsigned pid:2; + /** Interrupt On Complete */ + unsigned ioc:1; + /** Short Packet */ + unsigned sp:1; + /** Last */ + unsigned l:1; + /** Transmit Status */ + unsigned txsts:2; + /** Buffer Status */ + unsigned bs:2; + } b_iso_in; +#endif /* DWC_EN_ISOC */ +} dev_dma_desc_sts_t; + +/** + * DMA Descriptor structure + * + * DMA Descriptor structure contains two quadlets: + * Status quadlet and Data buffer pointer. + */ +typedef struct dwc_otg_dev_dma_desc { + /** DMA Descriptor status quadlet */ + dev_dma_desc_sts_t status; + /** DMA Descriptor data buffer pointer */ + uint32_t buf; +} dwc_otg_dev_dma_desc_t; + +/** + * The dwc_otg_dev_if structure contains information needed to manage + * the DWC_otg controller acting in device mode. It represents the + * programming view of the device-specific aspects of the controller. + */ +typedef struct dwc_otg_dev_if { + /** Pointer to device Global registers. + * Device Global Registers starting at offset 800h + */ + dwc_otg_device_global_regs_t *dev_global_regs; +#define DWC_DEV_GLOBAL_REG_OFFSET 0x800 + + /** + * Device Logical IN Endpoint-Specific Registers 900h-AFCh + */ + dwc_otg_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS]; +#define DWC_DEV_IN_EP_REG_OFFSET 0x900 +#define DWC_EP_REG_OFFSET 0x20 + + /** Device Logical OUT Endpoint-Specific Registers B00h-CFCh */ + dwc_otg_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS]; +#define DWC_DEV_OUT_EP_REG_OFFSET 0xB00 + + /* Device configuration information */ + uint8_t speed; /**< Device Speed 0: Unknown, 1: LS, 2:FS, 3: HS */ + uint8_t num_in_eps; /**< Number # of Tx EP range: 0-15 exept ep0 */ + uint8_t num_out_eps; /**< Number # of Rx EP range: 0-15 exept ep 0*/ + + /** Size of periodic FIFOs (Bytes) */ + uint16_t perio_tx_fifo_size[MAX_PERIO_FIFOS]; + + /** Size of Tx FIFOs (Bytes) */ + uint16_t tx_fifo_size[MAX_TX_FIFOS]; + + /** Thresholding enable flags and length varaiables **/ + uint16_t rx_thr_en; + uint16_t iso_tx_thr_en; + uint16_t non_iso_tx_thr_en; + + uint16_t rx_thr_length; + uint16_t tx_thr_length; + + /** + * Pointers to the DMA Descriptors for EP0 Control + * transfers (virtual and physical) + */ + + /** 2 descriptors for SETUP packets */ + dwc_dma_t dma_setup_desc_addr[2]; + dwc_otg_dev_dma_desc_t *setup_desc_addr[2]; + + /** Pointer to Descriptor with latest SETUP packet */ + dwc_otg_dev_dma_desc_t *psetup; + + /** Index of current SETUP handler descriptor */ + uint32_t setup_desc_index; + + /** Descriptor for Data In or Status In phases */ + dwc_dma_t dma_in_desc_addr; + dwc_otg_dev_dma_desc_t *in_desc_addr; + + /** Descriptor for Data Out or Status Out phases */ + dwc_dma_t dma_out_desc_addr; + dwc_otg_dev_dma_desc_t *out_desc_addr; + + /** Setup Packet Detected - if set clear NAK when queueing */ + uint32_t spd; + +} dwc_otg_dev_if_t; + +///////////////////////////////////////////////// +// Host Mode Register Structures +// +/** + * The Host Global Registers structure defines the size and relative + * field offsets for the Host Mode Global Registers. Host Global + * Registers offsets 400h-7FFh. +*/ +typedef struct dwc_otg_host_global_regs { + /** Host Configuration Register. Offset: 400h */ + volatile uint32_t hcfg; + /** Host Frame Interval Register. Offset: 404h */ + volatile uint32_t hfir; + /** Host Frame Number / Frame Remaining Register. Offset: 408h */ + volatile uint32_t hfnum; + /** Reserved. Offset: 40Ch */ + uint32_t reserved40C; + /** Host Periodic Transmit FIFO/ Queue Status Register. Offset: 410h */ + volatile uint32_t hptxsts; + /** Host All Channels Interrupt Register. Offset: 414h */ + volatile uint32_t haint; + /** Host All Channels Interrupt Mask Register. Offset: 418h */ + volatile uint32_t haintmsk; + /** Host Frame List Base Address Register . Offset: 41Ch */ + volatile uint32_t hflbaddr; +} dwc_otg_host_global_regs_t; + + +/** + * This union represents the bit fields in the Host Configuration Register. + * Read the register into the d32 member then set/clear the bits using + * the bit elements. Write the d32 member to the hcfg register. + */ +typedef union hcfg_data +{ + /** raw register data */ + uint32_t d32; + + /** register bits */ + struct + { + /** FS/LS Phy Clock Select */ + unsigned fslspclksel:2; +#define DWC_HCFG_30_60_MHZ 0 +#define DWC_HCFG_48_MHZ 1 +#define DWC_HCFG_6_MHZ 2 + + /** FS/LS Only Support */ + unsigned fslssupp:1; + unsigned reserved3_22 : 20; + /** Enable Scatter/gather DMA in Host mode */ + unsigned descdma : 1; + /** Frame List Entries */ + unsigned frlisten: 2; + /** Enable Periodic Scheduling */ + unsigned perschedena: 1; + /** Periodic Scheduling Enabled Status */ + unsigned perschedstat: 1; + } b; +} hcfg_data_t; + +/** + * This union represents the bit fields in the Host Frame Remaing/Number + * Register. + */ +typedef union hfir_data { + /** raw register data */ + uint32_t d32; + + /** register bits */ + struct { + unsigned frint:16; + unsigned reserved:16; + } b; +} hfir_data_t; + +/** + * This union represents the bit fields in the Host Frame Remaing/Number + * Register. + */ +typedef union hfnum_data { + /** raw register data */ + uint32_t d32; + + /** register bits */ + struct { + unsigned frnum:16; +#define DWC_HFNUM_MAX_FRNUM 0x3FFF + unsigned frrem:16; + } b; +} hfnum_data_t; + +typedef union hptxsts_data { + /** raw register data */ + uint32_t d32; + + /** register bits */ + struct { + unsigned ptxfspcavail:16; + unsigned ptxqspcavail:8; + /** Top of the Periodic Transmit Request Queue + * - bit 24 - Terminate (last entry for the selected channel) + * - bits 26:25 - Token Type + * - 2'b00 - Zero length + * - 2'b01 - Ping + * - 2'b10 - Disable + * - bits 30:27 - Channel Number + * - bit 31 - Odd/even microframe + */ + unsigned ptxqtop_terminate:1; + unsigned ptxqtop_token:2; + unsigned ptxqtop_chnum:4; + unsigned ptxqtop_odd:1; + } b; +} hptxsts_data_t; + +/** + * This union represents the bit fields in the Host Port Control and Status + * Register. Read the register into the d32 member then set/clear the + * bits using the bit elements. Write the d32 member to the + * hprt0 register. + */ +typedef union hprt0_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned prtconnsts:1; + unsigned prtconndet:1; + unsigned prtena:1; + unsigned prtenchng:1; + unsigned prtovrcurract:1; + unsigned prtovrcurrchng:1; + unsigned prtres:1; + unsigned prtsusp:1; + unsigned prtrst:1; + unsigned reserved9:1; + unsigned prtlnsts:2; + unsigned prtpwr:1; + unsigned prttstctl:4; + unsigned prtspd:2; +#define DWC_HPRT0_PRTSPD_HIGH_SPEED 0 +#define DWC_HPRT0_PRTSPD_FULL_SPEED 1 +#define DWC_HPRT0_PRTSPD_LOW_SPEED 2 + unsigned reserved19_31:13; + } b; +} hprt0_data_t; + +/** + * This union represents the bit fields in the Host All Interrupt + * Register. + */ +typedef union haint_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned ch0:1; + unsigned ch1:1; + unsigned ch2:1; + unsigned ch3:1; + unsigned ch4:1; + unsigned ch5:1; + unsigned ch6:1; + unsigned ch7:1; + unsigned ch8:1; + unsigned ch9:1; + unsigned ch10:1; + unsigned ch11:1; + unsigned ch12:1; + unsigned ch13:1; + unsigned ch14:1; + unsigned ch15:1; + unsigned reserved:16; + } b; + + struct { + unsigned chint:16; + unsigned reserved:16; + } b2; +} haint_data_t; + +/** + * This union represents the bit fields in the Host All Interrupt + * Register. + */ +typedef union haintmsk_data { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned ch0:1; + unsigned ch1:1; + unsigned ch2:1; + unsigned ch3:1; + unsigned ch4:1; + unsigned ch5:1; + unsigned ch6:1; + unsigned ch7:1; + unsigned ch8:1; + unsigned ch9:1; + unsigned ch10:1; + unsigned ch11:1; + unsigned ch12:1; + unsigned ch13:1; + unsigned ch14:1; + unsigned ch15:1; + unsigned reserved:16; + } b; + + struct { + unsigned chint:16; + unsigned reserved:16; + } b2; +} haintmsk_data_t; + +/** + * Host Channel Specific Registers. 500h-5FCh + */ +typedef struct dwc_otg_hc_regs +{ + /** Host Channel 0 Characteristic Register. Offset: 500h + (chan_num * 20h) + 00h */ + volatile uint32_t hcchar; + /** Host Channel 0 Split Control Register. Offset: 500h + (chan_num * 20h) + 04h */ + volatile uint32_t hcsplt; + /** Host Channel 0 Interrupt Register. Offset: 500h + (chan_num * 20h) + 08h */ + volatile uint32_t hcint; + /** Host Channel 0 Interrupt Mask Register. Offset: 500h + (chan_num * 20h) + 0Ch */ + volatile uint32_t hcintmsk; + /** Host Channel 0 Transfer Size Register. Offset: 500h + (chan_num * 20h) + 10h */ + volatile uint32_t hctsiz; + /** Host Channel 0 DMA Address Register. Offset: 500h + (chan_num * 20h) + 14h */ + volatile uint32_t hcdma; + volatile uint32_t reserved; + /** Host Channel 0 DMA Buffer Address Register. Offset: 500h + (chan_num * 20h) + 1Ch */ + volatile uint32_t hcdmab; +} dwc_otg_hc_regs_t; + +/** + * This union represents the bit fields in the Host Channel Characteristics + * Register. Read the register into the d32 member then set/clear the + * bits using the bit elements. Write the d32 member to the + * hcchar register. + */ +typedef union hcchar_data { + /** raw register data */ + uint32_t d32; + + /** register bits */ + struct { + /** Maximum packet size in bytes */ + unsigned mps:11; + + /** Endpoint number */ + unsigned epnum:4; + + /** 0: OUT, 1: IN */ + unsigned epdir:1; + + unsigned reserved:1; + + /** 0: Full/high speed device, 1: Low speed device */ + unsigned lspddev:1; + + /** 0: Control, 1: Isoc, 2: Bulk, 3: Intr */ + unsigned eptype:2; + + /** Packets per frame for periodic transfers. 0 is reserved. */ + unsigned multicnt:2; + + /** Device address */ + unsigned devaddr:7; + + /** + * Frame to transmit periodic transaction. + * 0: even, 1: odd + */ + unsigned oddfrm:1; + + /** Channel disable */ + unsigned chdis:1; + + /** Channel enable */ + unsigned chen:1; + } b; +} hcchar_data_t; + +typedef union hcsplt_data { + /** raw register data */ + uint32_t d32; + + /** register bits */ + struct { + /** Port Address */ + unsigned prtaddr:7; + + /** Hub Address */ + unsigned hubaddr:7; + + /** Transaction Position */ + unsigned xactpos:2; +#define DWC_HCSPLIT_XACTPOS_MID 0 +#define DWC_HCSPLIT_XACTPOS_END 1 +#define DWC_HCSPLIT_XACTPOS_BEGIN 2 +#define DWC_HCSPLIT_XACTPOS_ALL 3 + + /** Do Complete Split */ + unsigned compsplt:1; + + /** Reserved */ + unsigned reserved:14; + + /** Split Enble */ + unsigned spltena:1; + } b; +} hcsplt_data_t; + +/** + * This union represents the bit fields in the Host All Interrupt + * Register. + */ +typedef union hcint_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + /** Transfer Complete */ + unsigned xfercomp:1; + /** Channel Halted */ + unsigned chhltd:1; + /** AHB Error */ + unsigned ahberr:1; + /** STALL Response Received */ + unsigned stall:1; + /** NAK Response Received */ + unsigned nak:1; + /** ACK Response Received */ + unsigned ack:1; + /** NYET Response Received */ + unsigned nyet:1; + /** Transaction Err */ + unsigned xacterr:1; + /** Babble Error */ + unsigned bblerr:1; + /** Frame Overrun */ + unsigned frmovrun:1; + /** Data Toggle Error */ + unsigned datatglerr:1; + /** Buffer Not Available (only for DDMA mode) */ + unsigned bna : 1; + /** Exessive transaction error (only for DDMA mode) */ + unsigned xcs_xact : 1; + /** Frame List Rollover interrupt */ + unsigned frm_list_roll : 1; + /** Reserved */ + unsigned reserved14_31 : 18; + } b; +} hcint_data_t; + +/** + * This union represents the bit fields in the Host Channel Interrupt Mask + * Register. Read the register into the d32 member then set/clear the + * bits using the bit elements. Write the d32 member to the + * hcintmsk register. + */ +typedef union hcintmsk_data +{ + /** raw register data */ + uint32_t d32; + + /** register bits */ + struct + { + unsigned xfercompl : 1; + unsigned chhltd : 1; + unsigned ahberr : 1; + unsigned stall : 1; + unsigned nak : 1; + unsigned ack : 1; + unsigned nyet : 1; + unsigned xacterr : 1; + unsigned bblerr : 1; + unsigned frmovrun : 1; + unsigned datatglerr : 1; + unsigned bna : 1; + unsigned xcs_xact : 1; + unsigned frm_list_roll : 1; + unsigned reserved14_31 : 18; + } b; +} hcintmsk_data_t; + +/** + * This union represents the bit fields in the Host Channel Transfer Size + * Register. Read the register into the d32 member then set/clear the + * bits using the bit elements. Write the d32 member to the + * hcchar register. + */ + +typedef union hctsiz_data +{ + /** raw register data */ + uint32_t d32; + + /** register bits */ + struct + { + /** Total transfer size in bytes */ + unsigned xfersize:19; + + /** Data packets to transfer */ + unsigned pktcnt:10; + + /** + * Packet ID for next data packet + * 0: DATA0 + * 1: DATA2 + * 2: DATA1 + * 3: MDATA (non-Control), SETUP (Control) + */ + unsigned pid:2; +#define DWC_HCTSIZ_DATA0 0 +#define DWC_HCTSIZ_DATA1 2 +#define DWC_HCTSIZ_DATA2 1 +#define DWC_HCTSIZ_MDATA 3 +#define DWC_HCTSIZ_SETUP 3 + + /** Do PING protocol when 1 */ + unsigned dopng:1; + } b; + + /** register bits */ + struct + { + /** Scheduling information */ + unsigned schinfo : 8; + + /** Number of transfer descriptors. + * Max value: + * 64 in general, + * 256 only for HS isochronous endpoint. + */ + unsigned ntd : 8; + + /** Data packets to transfer */ + unsigned reserved16_28 : 13; + + /** + * Packet ID for next data packet + * 0: DATA0 + * 1: DATA2 + * 2: DATA1 + * 3: MDATA (non-Control) + */ + unsigned pid : 2; + + /** Do PING protocol when 1 */ + unsigned dopng : 1; + } b_ddma; +} hctsiz_data_t; + + +/** + * This union represents the bit fields in the Host DMA Address + * Register used in Descriptor DMA mode. + */ +typedef union hcdma_data +{ + /** raw register data */ + uint32_t d32; + /** register bits */ + struct + { + unsigned reserved0_2 : 3; + /** Current Transfer Descriptor. Not used for ISOC */ + unsigned ctd : 8; + /** Start Address of Descriptor List */ + unsigned dma_addr : 21; + } b; +} hcdma_data_t; + +/** + * This union represents the bit fields in the DMA Descriptor + * status quadlet for host mode. Read the quadlet into the d32 member then + * set/clear the bits using the bit elements. + */ +typedef union host_dma_desc_sts +{ + /** raw register data */ + uint32_t d32; + /** quadlet bits */ + + /* for non-isochronous */ + struct { + /** Number of bytes */ + unsigned n_bytes : 17; + /** QTD offset to jump when Short Packet received - only for IN EPs */ + unsigned qtd_offset : 6; + /** + * Set to request the core to jump to alternate QTD if + * Short Packet received - only for IN EPs + */ + unsigned a_qtd : 1; + /** + * Setup Packet bit. When set indicates that buffer contains + * setup packet. + */ + unsigned sup : 1; + /** Interrupt On Complete */ + unsigned ioc : 1; + /** End of List */ + unsigned eol : 1; + unsigned reserved27 : 1; + /** Rx/Tx Status */ + unsigned sts : 2; + #define DMA_DESC_STS_PKTERR 1 + unsigned reserved30 : 1; + /** Active Bit */ + unsigned a : 1; + } b; + /* for isochronous */ + struct { + /** Number of bytes */ + unsigned n_bytes : 12; + unsigned reserved12_24 : 13; + /** Interrupt On Complete */ + unsigned ioc : 1; + unsigned reserved26_27 : 2; + /** Rx/Tx Status */ + unsigned sts : 2; + unsigned reserved30 : 1; + /** Active Bit */ + unsigned a : 1; + } b_isoc; +} host_dma_desc_sts_t; + +#define MAX_DMA_DESC_SIZE 131071 +#define MAX_DMA_DESC_NUM_GENERIC 64 +#define MAX_DMA_DESC_NUM_HS_ISOC 256 +#define MAX_FRLIST_EN_NUM 64 +/** + * Host-mode DMA Descriptor structure + * + * DMA Descriptor structure contains two quadlets: + * Status quadlet and Data buffer pointer. + */ +typedef struct dwc_otg_host_dma_desc +{ + /** DMA Descriptor status quadlet */ + host_dma_desc_sts_t status; + /** DMA Descriptor data buffer pointer */ + uint32_t buf; +} dwc_otg_host_dma_desc_t; + +/** OTG Host Interface Structure. + * + * The OTG Host Interface Structure structure contains information + * needed to manage the DWC_otg controller acting in host mode. It + * represents the programming view of the host-specific aspects of the + * controller. + */ +typedef struct dwc_otg_host_if { + /** Host Global Registers starting at offset 400h.*/ + dwc_otg_host_global_regs_t *host_global_regs; +#define DWC_OTG_HOST_GLOBAL_REG_OFFSET 0x400 + + /** Host Port 0 Control and Status Register */ + volatile uint32_t *hprt0; +#define DWC_OTG_HOST_PORT_REGS_OFFSET 0x440 + + /** Host Channel Specific Registers at offsets 500h-5FCh. */ + dwc_otg_hc_regs_t *hc_regs[MAX_EPS_CHANNELS]; +#define DWC_OTG_HOST_CHAN_REGS_OFFSET 0x500 +#define DWC_OTG_CHAN_REGS_OFFSET 0x20 + + /* Host configuration information */ + /** Number of Host Channels (range: 1-16) */ + uint8_t num_host_channels; + /** Periodic EPs supported (0: no, 1: yes) */ + uint8_t perio_eps_supported; + /** Periodic Tx FIFO Size (Only 1 host periodic Tx FIFO) */ + uint16_t perio_tx_fifo_size; + +} dwc_otg_host_if_t; + +/** + * This union represents the bit fields in the Power and Clock Gating Control + * Register. Read the register into the d32 member then set/clear the + * bits using the bit elements. + */ +typedef union pcgcctl_data { + /** raw register data */ + uint32_t d32; + + /** register bits */ + struct { + /** Stop Pclk */ + unsigned stoppclk:1; + /** Gate Hclk */ + unsigned gatehclk:1; + /** Power Clamp */ + unsigned pwrclmp:1; + /** Reset Power Down Modules */ + unsigned rstpdwnmodule:1; + /** PHY Suspended */ + unsigned physuspended:1; + /** Enable Sleep Clock Gating (Enbl_L1Gating) */ + unsigned enbl_sleep_gating:1; + /** PHY In Sleep (PhySleep) */ + unsigned phy_in_sleep:1; + /** Deep Sleep*/ + unsigned deep_sleep:1; + + unsigned reserved31_8:24; + } b; +} pcgcctl_data_t; + +#endif diff --git a/drivers/usb/host/dwc_otg/test/Makefile b/drivers/usb/host/dwc_otg/test/Makefile new file mode 100644 index 000000000000..fc453759dea3 --- /dev/null +++ b/drivers/usb/host/dwc_otg/test/Makefile @@ -0,0 +1,16 @@ + +PERL=/usr/bin/perl +PL_TESTS=test_sysfs.pl test_mod_param.pl + +.PHONY : test +test : perl_tests + +perl_tests : + @echo + @echo Running perl tests + @for test in $(PL_TESTS); do \ + if $(PERL) ./$$test ; then \ + echo "=======> $$test, PASSED" ; \ + else echo "=======> $$test, FAILED" ; \ + fi \ + done diff --git a/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm b/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm new file mode 100644 index 000000000000..233b04ad870c --- /dev/null +++ b/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm @@ -0,0 +1,337 @@ +package dwc_otg_test; + +use strict; +use Exporter (); + +use vars qw(@ISA @EXPORT +$sysfsdir $paramdir $errors $params +); + +@ISA = qw(Exporter); + +# +# Globals +# +$sysfsdir = "/sys/devices/lm0"; +$paramdir = "/sys/module/dwc_otg"; +$errors = 0; + +$params = [ + { + NAME => "otg_cap", + DEFAULT => 0, + ENUM => [], + LOW => 0, + HIGH => 2 + }, + { + NAME => "dma_enable", + DEFAULT => 0, + ENUM => [], + LOW => 0, + HIGH => 1 + }, + { + NAME => "dma_burst_size", + DEFAULT => 32, + ENUM => [1, 4, 8, 16, 32, 64, 128, 256], + LOW => 1, + HIGH => 256 + }, + { + NAME => "host_speed", + DEFAULT => 0, + ENUM => [], + LOW => 0, + HIGH => 1 + }, + { + NAME => "host_support_fs_ls_low_power", + DEFAULT => 0, + ENUM => [], + LOW => 0, + HIGH => 1 + }, + { + NAME => "host_ls_low_power_phy_clk", + DEFAULT => 0, + ENUM => [], + LOW => 0, + HIGH => 1 + }, + { + NAME => "dev_speed", + DEFAULT => 0, + ENUM => [], + LOW => 0, + HIGH => 1 + }, + { + NAME => "enable_dynamic_fifo", + DEFAULT => 1, + ENUM => [], + LOW => 0, + HIGH => 1 + }, + { + NAME => "data_fifo_size", + DEFAULT => 8192, + ENUM => [], + LOW => 32, + HIGH => 32768 + }, + { + NAME => "dev_rx_fifo_size", + DEFAULT => 1064, + ENUM => [], + LOW => 16, + HIGH => 32768 + }, + { + NAME => "dev_nperio_tx_fifo_size", + DEFAULT => 1024, + ENUM => [], + LOW => 16, + HIGH => 32768 + }, + { + NAME => "dev_perio_tx_fifo_size_1", + DEFAULT => 256, + ENUM => [], + LOW => 4, + HIGH => 768 + }, + { + NAME => "dev_perio_tx_fifo_size_2", + DEFAULT => 256, + ENUM => [], + LOW => 4, + HIGH => 768 + }, + { + NAME => "dev_perio_tx_fifo_size_3", + DEFAULT => 256, + ENUM => [], + LOW => 4, + HIGH => 768 + }, + { + NAME => "dev_perio_tx_fifo_size_4", + DEFAULT => 256, + ENUM => [], + LOW => 4, + HIGH => 768 + }, + { + NAME => "dev_perio_tx_fifo_size_5", + DEFAULT => 256, + ENUM => [], + LOW => 4, + HIGH => 768 + }, + { + NAME => "dev_perio_tx_fifo_size_6", + DEFAULT => 256, + ENUM => [], + LOW => 4, + HIGH => 768 + }, + { + NAME => "dev_perio_tx_fifo_size_7", + DEFAULT => 256, + ENUM => [], + LOW => 4, + HIGH => 768 + }, + { + NAME => "dev_perio_tx_fifo_size_8", + DEFAULT => 256, + ENUM => [], + LOW => 4, + HIGH => 768 + }, + { + NAME => "dev_perio_tx_fifo_size_9", + DEFAULT => 256, + ENUM => [], + LOW => 4, + HIGH => 768 + }, + { + NAME => "dev_perio_tx_fifo_size_10", + DEFAULT => 256, + ENUM => [], + LOW => 4, + HIGH => 768 + }, + { + NAME => "dev_perio_tx_fifo_size_11", + DEFAULT => 256, + ENUM => [], + LOW => 4, + HIGH => 768 + }, + { + NAME => "dev_perio_tx_fifo_size_12", + DEFAULT => 256, + ENUM => [], + LOW => 4, + HIGH => 768 + }, + { + NAME => "dev_perio_tx_fifo_size_13", + DEFAULT => 256, + ENUM => [], + LOW => 4, + HIGH => 768 + }, + { + NAME => "dev_perio_tx_fifo_size_14", + DEFAULT => 256, + ENUM => [], + LOW => 4, + HIGH => 768 + }, + { + NAME => "dev_perio_tx_fifo_size_15", + DEFAULT => 256, + ENUM => [], + LOW => 4, + HIGH => 768 + }, + { + NAME => "host_rx_fifo_size", + DEFAULT => 1024, + ENUM => [], + LOW => 16, + HIGH => 32768 + }, + { + NAME => "host_nperio_tx_fifo_size", + DEFAULT => 1024, + ENUM => [], + LOW => 16, + HIGH => 32768 + }, + { + NAME => "host_perio_tx_fifo_size", + DEFAULT => 1024, + ENUM => [], + LOW => 16, + HIGH => 32768 + }, + { + NAME => "max_transfer_size", + DEFAULT => 65535, + ENUM => [], + LOW => 2047, + HIGH => 65535 + }, + { + NAME => "max_packet_count", + DEFAULT => 511, + ENUM => [], + LOW => 15, + HIGH => 511 + }, + { + NAME => "host_channels", + DEFAULT => 12, + ENUM => [], + LOW => 1, + HIGH => 16 + }, + { + NAME => "dev_endpoints", + DEFAULT => 6, + ENUM => [], + LOW => 1, + HIGH => 15 + }, + { + NAME => "phy_type", + DEFAULT => 1, + ENUM => [], + LOW => 0, + HIGH => 2 + }, + { + NAME => "phy_utmi_width", + DEFAULT => 16, + ENUM => [8, 16], + LOW => 8, + HIGH => 16 + }, + { + NAME => "phy_ulpi_ddr", + DEFAULT => 0, + ENUM => [], + LOW => 0, + HIGH => 1 + }, + ]; + + +# +# +sub check_arch { + $_ = `uname -m`; + chomp; + unless (m/armv4tl/) { + warn "# \n# Can't execute on $_. Run on integrator platform.\n# \n"; + return 0; + } + return 1; +} + +# +# +sub load_module { + my $params = shift; + print "\nRemoving Module\n"; + system "rmmod dwc_otg"; + print "Loading Module\n"; + if ($params ne "") { + print "Module Parameters: $params\n"; + } + if (system("modprobe dwc_otg $params")) { + warn "Unable to load module\n"; + return 0; + } + return 1; +} + +# +# +sub test_status { + my $arg = shift; + + print "\n"; + + if (defined $arg) { + warn "WARNING: $arg\n"; + } + + if ($errors > 0) { + warn "TEST FAILED with $errors errors\n"; + return 0; + } else { + print "TEST PASSED\n"; + return 0 if (defined $arg); + } + return 1; +} + +# +# +@EXPORT = qw( +$sysfsdir +$paramdir +$params +$errors +check_arch +load_module +test_status +); + +1; diff --git a/drivers/usb/host/dwc_otg/test/test_mod_param.pl b/drivers/usb/host/dwc_otg/test/test_mod_param.pl new file mode 100644 index 000000000000..e887dce5bc1e --- /dev/null +++ b/drivers/usb/host/dwc_otg/test/test_mod_param.pl @@ -0,0 +1,133 @@ +#!/usr/bin/perl -w +# +# Run this program on the integrator. +# +# - Tests module parameter default values. +# - Tests setting of valid module parameter values via modprobe. +# - Tests invalid module parameter values. +# ----------------------------------------------------------------------------- +use strict; +use dwc_otg_test; + +check_arch() or die; + +# +# +sub test { + my ($param,$expected) = @_; + my $value = get($param); + + if ($value == $expected) { + print "$param = $value, okay\n"; + } + + else { + warn "ERROR: value of $param != $expected, $value\n"; + $errors ++; + } +} + +# +# +sub get { + my $param = shift; + my $tmp = `cat $paramdir/$param`; + chomp $tmp; + return $tmp; +} + +# +# +sub test_main { + + print "\nTesting Module Parameters\n"; + + load_module("") or die; + + # Test initial values + print "\nTesting Default Values\n"; + foreach (@{$params}) { + test ($_->{NAME}, $_->{DEFAULT}); + } + + # Test low value + print "\nTesting Low Value\n"; + my $cmd_params = ""; + foreach (@{$params}) { + $cmd_params = $cmd_params . "$_->{NAME}=$_->{LOW} "; + } + load_module($cmd_params) or die; + + foreach (@{$params}) { + test ($_->{NAME}, $_->{LOW}); + } + + # Test high value + print "\nTesting High Value\n"; + $cmd_params = ""; + foreach (@{$params}) { + $cmd_params = $cmd_params . "$_->{NAME}=$_->{HIGH} "; + } + load_module($cmd_params) or die; + + foreach (@{$params}) { + test ($_->{NAME}, $_->{HIGH}); + } + + # Test Enum + print "\nTesting Enumerated\n"; + foreach (@{$params}) { + if (defined $_->{ENUM}) { + my $value; + foreach $value (@{$_->{ENUM}}) { + $cmd_params = "$_->{NAME}=$value"; + load_module($cmd_params) or die; + test ($_->{NAME}, $value); + } + } + } + + # Test Invalid Values + print "\nTesting Invalid Values\n"; + $cmd_params = ""; + foreach (@{$params}) { + $cmd_params = $cmd_params . sprintf "$_->{NAME}=%d ", $_->{LOW}-1; + } + load_module($cmd_params) or die; + + foreach (@{$params}) { + test ($_->{NAME}, $_->{DEFAULT}); + } + + $cmd_params = ""; + foreach (@{$params}) { + $cmd_params = $cmd_params . sprintf "$_->{NAME}=%d ", $_->{HIGH}+1; + } + load_module($cmd_params) or die; + + foreach (@{$params}) { + test ($_->{NAME}, $_->{DEFAULT}); + } + + print "\nTesting Enumerated\n"; + foreach (@{$params}) { + if (defined $_->{ENUM}) { + my $value; + foreach $value (@{$_->{ENUM}}) { + $value = $value + 1; + $cmd_params = "$_->{NAME}=$value"; + load_module($cmd_params) or die; + test ($_->{NAME}, $_->{DEFAULT}); + $value = $value - 2; + $cmd_params = "$_->{NAME}=$value"; + load_module($cmd_params) or die; + test ($_->{NAME}, $_->{DEFAULT}); + } + } + } + + test_status() or die; +} + +test_main(); +0; diff --git a/drivers/usb/host/dwc_otg/test/test_sysfs.pl b/drivers/usb/host/dwc_otg/test/test_sysfs.pl new file mode 100644 index 000000000000..abcf284fecf9 --- /dev/null +++ b/drivers/usb/host/dwc_otg/test/test_sysfs.pl @@ -0,0 +1,193 @@ +#!/usr/bin/perl -w +# +# Run this program on the integrator +# - Tests select sysfs attributes. +# - Todo ... test more attributes, hnp/srp, buspower/bussuspend, etc. +# ----------------------------------------------------------------------------- +use strict; +use dwc_otg_test; + +check_arch() or die; + +# +# +sub test { + my ($attr,$expected) = @_; + my $string = get($attr); + + if ($string eq $expected) { + printf("$attr = $string, okay\n"); + } + else { + warn "ERROR: value of $attr != $expected, $string\n"; + $errors ++; + } +} + +# +# +sub set { + my ($reg, $value) = @_; + system "echo $value > $sysfsdir/$reg"; +} + +# +# +sub get { + my $attr = shift; + my $string = `cat $sysfsdir/$attr`; + chomp $string; + if ($string =~ m/\s\=\s/) { + my $tmp; + ($tmp, $string) = split /\s=\s/, $string; + } + return $string; +} + +# +# +sub test_main { + print("\nTesting Sysfs Attributes\n"); + + load_module("") or die; + + # Test initial values of regoffset/regvalue/guid/gsnpsid + print("\nTesting Default Values\n"); + + test("regoffset", "0xffffffff"); + test("regvalue", "invalid offset"); + test("guid", "0x12345678"); # this will fail if it has been changed + test("gsnpsid", "0x4f54200a"); + + # Test operation of regoffset/regvalue + print("\nTesting regoffset\n"); + set('regoffset', '5a5a5a5a'); + test("regoffset", "0xffffffff"); + + set('regoffset', '0'); + test("regoffset", "0x00000000"); + + set('regoffset', '40000'); + test("regoffset", "0x00000000"); + + set('regoffset', '3ffff'); + test("regoffset", "0x0003ffff"); + + set('regoffset', '1'); + test("regoffset", "0x00000001"); + + print("\nTesting regvalue\n"); + set('regoffset', '3c'); + test("regvalue", "0x12345678"); + set('regvalue', '5a5a5a5a'); + test("regvalue", "0x5a5a5a5a"); + set('regvalue','a5a5a5a5'); + test("regvalue", "0xa5a5a5a5"); + set('guid','12345678'); + + # Test HNP Capable + print("\nTesting HNP Capable bit\n"); + set('hnpcapable', '1'); + test("hnpcapable", "0x1"); + set('hnpcapable','0'); + test("hnpcapable", "0x0"); + + set('regoffset','0c'); + + my $old = get('gusbcfg'); + print("setting hnpcapable\n"); + set('hnpcapable', '1'); + test("hnpcapable", "0x1"); + test('gusbcfg', sprintf "0x%08x", (oct ($old) | (1<<9))); + test('regvalue', sprintf "0x%08x", (oct ($old) | (1<<9))); + + $old = get('gusbcfg'); + print("clearing hnpcapable\n"); + set('hnpcapable', '0'); + test("hnpcapable", "0x0"); + test ('gusbcfg', sprintf "0x%08x", oct ($old) & (~(1<<9))); + test ('regvalue', sprintf "0x%08x", oct ($old) & (~(1<<9))); + + # Test SRP Capable + print("\nTesting SRP Capable bit\n"); + set('srpcapable', '1'); + test("srpcapable", "0x1"); + set('srpcapable','0'); + test("srpcapable", "0x0"); + + set('regoffset','0c'); + + $old = get('gusbcfg'); + print("setting srpcapable\n"); + set('srpcapable', '1'); + test("srpcapable", "0x1"); + test('gusbcfg', sprintf "0x%08x", (oct ($old) | (1<<8))); + test('regvalue', sprintf "0x%08x", (oct ($old) | (1<<8))); + + $old = get('gusbcfg'); + print("clearing srpcapable\n"); + set('srpcapable', '0'); + test("srpcapable", "0x0"); + test('gusbcfg', sprintf "0x%08x", oct ($old) & (~(1<<8))); + test('regvalue', sprintf "0x%08x", oct ($old) & (~(1<<8))); + + # Test GGPIO + print("\nTesting GGPIO\n"); + set('ggpio','5a5a5a5a'); + test('ggpio','0x5a5a0000'); + set('ggpio','a5a5a5a5'); + test('ggpio','0xa5a50000'); + set('ggpio','11110000'); + test('ggpio','0x11110000'); + set('ggpio','00001111'); + test('ggpio','0x00000000'); + + # Test DEVSPEED + print("\nTesting DEVSPEED\n"); + set('regoffset','800'); + $old = get('regvalue'); + set('devspeed','0'); + test('devspeed','0x0'); + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3))); + set('devspeed','1'); + test('devspeed','0x1'); + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 1)); + set('devspeed','2'); + test('devspeed','0x2'); + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 2)); + set('devspeed','3'); + test('devspeed','0x3'); + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 3)); + set('devspeed','4'); + test('devspeed','0x0'); + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3))); + set('devspeed','5'); + test('devspeed','0x1'); + test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 1)); + + + # mode Returns the current mode:0 for device mode1 for host mode Read + # hnp Initiate the Host Negotiation Protocol. Read returns the status. Read/Write + # srp Initiate the Session Request Protocol. Read returns the status. Read/Write + # buspower Get or Set the Power State of the bus (0 - Off or 1 - On) Read/Write + # bussuspend Suspend the USB bus. Read/Write + # busconnected Get the connection status of the bus Read + + # gotgctl Get or set the Core Control Status Register. Read/Write + ## gusbcfg Get or set the Core USB Configuration Register Read/Write + # grxfsiz Get or set the Receive FIFO Size Register Read/Write + # gnptxfsiz Get or set the non-periodic Transmit Size Register Read/Write + # gpvndctl Get or set the PHY Vendor Control Register Read/Write + ## ggpio Get the value in the lower 16-bits of the General Purpose IO Register or Set the upper 16 bits. Read/Write + ## guid Get or set the value of the User ID Register Read/Write + ## gsnpsid Get the value of the Synopsys ID Regester Read + ## devspeed Get or set the device speed setting in the DCFG register Read/Write + # enumspeed Gets the device enumeration Speed. Read + # hptxfsiz Get the value of the Host Periodic Transmit FIFO Read + # hprt0 Get or Set the value in the Host Port Control and Status Register Read/Write + + test_status("TEST NYI") or die; +} + +test_main(); +0; -- GitLab