Changeset 7978d1e7 in mainline
- Timestamp:
- 2014-08-14T08:56:27Z (10 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 8d070710
- Parents:
- b229062
- Location:
- uspace/drv/audio/hdaudio
- Files:
-
- 1 added
- 5 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/audio/hdaudio/hdactl.c
rb229062 r7978d1e7 33 33 */ 34 34 35 #include <as.h> 36 #include <async.h> 37 #include <bitops.h> 35 38 #include <ddf/log.h> 39 #include <ddi.h> 40 #include <errno.h> 41 #include <macros.h> 36 42 #include <stdint.h> 37 43 38 44 #include "hdactl.h" 39 45 #include "regif.h" 40 #include "hdaudio_regs.h" 46 #include "spec/regs.h" 47 48 enum { 49 ctrl_init_wait_max = 10, 50 codec_enum_wait_us = 512 51 }; 52 53 /** Select an appropriate CORB/RIRB size. 54 * 55 * We always use the largest available size. In @a sizecap each of bits 56 * 0, 1, 2 determine whether one of the supported size (0 == 2 enries, 57 * 1 == 16 entries, 2 == 256 entries) is supported. @a *selsz is set to 58 * one of 0, 1, 2 on success. 59 * 60 * @param sizecap CORB/RIRB Size Capability 61 * @param selsz Place to store CORB/RIRB Size 62 * @return EOK on success, EINVAL if sizecap has no valid bits set 63 * 64 */ 65 static int hda_rb_size_select(uint8_t sizecap, uint8_t *selsz) 66 { 67 int i; 68 69 for (i = 2; i >= 0; --i) { 70 if ((sizecap & BIT_V(uint8_t, i)) != 0) { 71 *selsz = i; 72 return EOK; 73 } 74 } 75 76 return EINVAL; 77 } 78 79 static size_t hda_rb_entries(uint8_t selsz) 80 { 81 switch (selsz) { 82 case 0: 83 return 2; 84 case 1: 85 return 16; 86 case 2: 87 return 256; 88 default: 89 assert(false); 90 return 0; 91 } 92 } 93 94 /** Initialize the CORB */ 95 static int hda_corb_init(hda_t *hda) 96 { 97 uint8_t ctl; 98 uint8_t corbsz; 99 uint8_t sizecap; 100 uint8_t selsz; 101 bool ok64bit; 102 int rc; 103 104 ddf_msg(LVL_NOTE, "hda_corb_init()"); 105 106 /* Stop CORB if not stopped. */ 107 ctl = hda_reg8_read(&hda->regs->corbctl); 108 if ((ctl & BIT_V(uint8_t, corbctl_run)) != 0) { 109 ddf_msg(LVL_NOTE, "CORB is enabled, disabling first."); 110 hda_reg8_write(&hda->regs->corbctl, ctl & ~BIT_V(uint8_t, 111 corbctl_run)); 112 } 113 114 /* Determine CORB size and allocate CORB buffer */ 115 corbsz = hda_reg8_read(&hda->regs->corbsize); 116 sizecap = BIT_RANGE_EXTRACT(uint8_t, corbsize_cap_h, 117 corbsize_cap_l, corbsz); 118 rc = hda_rb_size_select(sizecap, &selsz); 119 if (rc != EOK) { 120 ddf_msg(LVL_ERROR, "Invalid CORB Size Capability"); 121 goto error; 122 } 123 corbsz = corbsz & ~BIT_RANGE(uint8_t, corbsize_size_h, corbsize_size_l); 124 corbsz = corbsz | selsz; 125 126 ddf_msg(LVL_NOTE, "Setting CORB Size register to 0x%x", corbsz); 127 hda_reg8_write(&hda->regs->corbsize, corbsz); 128 hda->ctl->corb_entries = hda_rb_entries(selsz); 129 130 ddf_msg(LVL_NOTE, "Read GCAP"); 131 uint16_t gcap = hda_reg16_read(&hda->regs->gcap); 132 ok64bit = (gcap & BIT_V(uint8_t, gcap_64ok)) != 0; 133 ddf_msg(LVL_NOTE, "GCAP: 0x%x (64OK=%d)", gcap, ok64bit); 134 135 /* 136 * CORB must be aligned to 128 bytes. If 64OK is not set, 137 * it must be within the 32-bit address space. 138 */ 139 hda->ctl->corb_virt = AS_AREA_ANY; 140 rc = dmamem_map_anonymous(hda->ctl->corb_entries * sizeof(uint32_t), 141 ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE, 0, 142 &hda->ctl->corb_phys, &hda->ctl->corb_virt); 143 144 ddf_msg(LVL_NOTE, "Set CORB base registers"); 145 146 /* Update CORB base registers */ 147 hda_reg32_write(&hda->regs->corblbase, LOWER32(hda->ctl->corb_phys)); 148 hda_reg32_write(&hda->regs->corbubase, UPPER32(hda->ctl->corb_phys)); 149 150 ddf_msg(LVL_NOTE, "Rset CORB Read/Write pointers"); 151 152 /* Reset CORB Read Pointer */ 153 hda_reg16_write(&hda->regs->corbrp, BIT_V(uint16_t, corbrp_rst)); 154 155 /* Reset CORB Write Poitner */ 156 hda_reg16_write(&hda->regs->corbwp, 0); 157 158 ddf_msg(LVL_NOTE, "CORB initialized"); 159 return EOK; 160 error: 161 return EIO; 162 } 163 164 /** Initialize the RIRB */ 165 static int hda_rirb_init(hda_t *hda) 166 { 167 uint8_t ctl; 168 uint8_t rirbsz; 169 uint8_t sizecap; 170 uint8_t selsz; 171 bool ok64bit; 172 int rc; 173 174 ddf_msg(LVL_NOTE, "hda_rirb_init()"); 175 176 /* Stop RIRB if not stopped. */ 177 ctl = hda_reg8_read(&hda->regs->rirbctl); 178 if ((ctl & BIT_V(uint8_t, rirbctl_run)) != 0) { 179 ddf_msg(LVL_NOTE, "RIRB is enabled, disabling first."); 180 hda_reg8_write(&hda->regs->corbctl, ctl & ~BIT_V(uint8_t, 181 rirbctl_run)); 182 } 183 184 /* Determine RIRB size and allocate RIRB buffer */ 185 rirbsz = hda_reg8_read(&hda->regs->rirbsize); 186 sizecap = BIT_RANGE_EXTRACT(uint8_t, rirbsize_cap_h, 187 rirbsize_cap_l, rirbsz); 188 rc = hda_rb_size_select(sizecap, &selsz); 189 if (rc != EOK) { 190 ddf_msg(LVL_ERROR, "Invalid RIRB Size Capability"); 191 goto error; 192 } 193 rirbsz = rirbsz & ~BIT_RANGE(uint8_t, rirbsize_size_h, rirbsize_size_l); 194 rirbsz = rirbsz | selsz; 195 196 ddf_msg(LVL_NOTE, "Setting RIRB Size register to 0x%x", rirbsz); 197 hda_reg8_write(&hda->regs->rirbsize, rirbsz); 198 hda->ctl->rirb_entries = hda_rb_entries(selsz); 199 200 ddf_msg(LVL_NOTE, "Read GCAP"); 201 uint16_t gcap = hda_reg16_read(&hda->regs->gcap); 202 ok64bit = (gcap & BIT_V(uint8_t, gcap_64ok)) != 0; 203 ddf_msg(LVL_NOTE, "GCAP: 0x%x (64OK=%d)", gcap, ok64bit); 204 205 /* 206 * RIRB must be aligned to 128 bytes. If 64OK is not set, 207 * it must be within the 32-bit address space. 208 */ 209 hda->ctl->rirb_virt = AS_AREA_ANY; 210 rc = dmamem_map_anonymous(hda->ctl->rirb_entries * sizeof(uint64_t), 211 ok64bit ? 0 : DMAMEM_4GiB, AS_AREA_READ | AS_AREA_WRITE, 0, 212 &hda->ctl->rirb_phys, &hda->ctl->rirb_virt); 213 214 ddf_msg(LVL_NOTE, "Set RIRB base registers"); 215 216 /* Update RIRB base registers */ 217 hda_reg32_write(&hda->regs->rirblbase, LOWER32(hda->ctl->rirb_phys)); 218 hda_reg32_write(&hda->regs->rirbubase, UPPER32(hda->ctl->rirb_phys)); 219 220 ddf_msg(LVL_NOTE, "Rset RIRB Write pointer"); 221 222 /* Reset RIRB Write Pointer */ 223 hda_reg16_write(&hda->regs->rirbwp, BIT_V(uint16_t, rirbwp_rst)); 224 225 ddf_msg(LVL_NOTE, "RIRB initialized"); 226 return EOK; 227 error: 228 return EIO; 229 } 41 230 42 231 hda_ctl_t *hda_ctl_init(hda_t *hda) 43 232 { 44 233 hda_ctl_t *ctl; 234 uint32_t gctl; 235 int cnt; 236 int rc; 45 237 46 238 ctl = calloc(1, sizeof(hda_ctl_t)); … … 48 240 return NULL; 49 241 242 hda->ctl = ctl; 243 50 244 uint8_t vmaj = hda_reg8_read(&hda->regs->vmaj); 51 245 uint8_t vmin = hda_reg8_read(&hda->regs->vmin); … … 58 252 } 59 253 254 ddf_msg(LVL_NOTE, "reg 0x%zx STATESTS = 0x%x", 255 (void *)&hda->regs->statests - (void *)hda->regs, hda_reg16_read(&hda->regs->statests)); 256 257 gctl = hda_reg32_read(&hda->regs->gctl); 258 if ((gctl & BIT_V(uint32_t, gctl_crst)) != 0) { 259 ddf_msg(LVL_NOTE, "Controller not in reset. Resetting."); 260 hda_reg32_write(&hda->regs->gctl, gctl & ~BIT_V(uint32_t, gctl_crst)); 261 } 262 263 ddf_msg(LVL_NOTE, "Taking controller out of reset."); 264 hda_reg32_write(&hda->regs->gctl, gctl | BIT_V(uint32_t, gctl_crst)); 265 266 /* Wait for CRST to read as 1 */ 267 cnt = ctrl_init_wait_max; 268 while (cnt > 0) { 269 gctl = hda_reg32_read(&hda->regs->gctl); 270 if ((gctl & BIT_V(uint32_t, gctl_crst)) != 0) { 271 ddf_msg(LVL_NOTE, "gctl=0x%x", gctl); 272 break; 273 } 274 275 ddf_msg(LVL_NOTE, "Waiting for controller to initialize."); 276 async_usleep(100*1000); 277 --cnt; 278 } 279 280 if (cnt == 0) { 281 ddf_msg(LVL_ERROR, "Timed out waiting for controller to come up."); 282 goto error; 283 } 284 285 ddf_msg(LVL_NOTE, "Controller is out of reset."); 286 287 /* Give codecs enough time to enumerate themselves */ 288 async_usleep(codec_enum_wait_us); 289 290 ddf_msg(LVL_NOTE, "STATESTS = 0x%x", 291 hda_reg16_read(&hda->regs->statests)); 292 293 rc = hda_corb_init(hda); 294 if (rc != EOK) 295 goto error; 296 297 rc = hda_rirb_init(hda); 298 if (rc != EOK) 299 goto error; 300 60 301 return ctl; 61 302 error: 62 303 free(ctl); 304 hda->ctl = NULL; 63 305 return NULL; 64 306 } -
uspace/drv/audio/hdaudio/hdactl.h
rb229062 r7978d1e7 39 39 40 40 typedef struct hda_ctl { 41 41 uintptr_t corb_phys; 42 void *corb_virt; 43 size_t corb_entries; 44 45 uintptr_t rirb_phys; 46 void *rirb_virt; 47 size_t rirb_entries; 42 48 } hda_ctl_t; 43 49 -
uspace/drv/audio/hdaudio/hdaudio.c
rb229062 r7978d1e7 44 44 #include "hdactl.h" 45 45 #include "hdaudio.h" 46 #include " hdaudio_regs.h"46 #include "spec/regs.h" 47 47 48 48 #define NAME "hdaudio" … … 71 71 ddf_fun_t *fun_a; 72 72 hda_t *hda = NULL; 73 const char *dev_name;74 73 hw_res_list_parsed_t res; 75 74 void *regs; 76 75 int rc; 77 76 78 dev_name = ddf_dev_get_name(dev);79 77 ddf_msg(LVL_NOTE, "hda_dev_add()"); 80 78 … … 127 125 hda->regs = (hda_regs_t *)regs; 128 126 129 hda->ctl = hda_ctl_init(hda); 130 if (hda->ctl == NULL) { 127 if (hda_ctl_init(hda) == NULL) { 131 128 rc = EIO; 132 129 goto error; … … 151 148 152 149 ddf_fun_add_to_category(fun_a, "virtual"); 153 154 ddf_msg(LVL_DEBUG, "Device `%s' accepted.", dev_name);155 150 return EOK; 156 151 error: -
uspace/drv/audio/hdaudio/hdaudio.h
rb229062 r7978d1e7 30 30 * @{ 31 31 */ 32 /** @file High Definition Audio controller32 /** @file High Definition Audio driver 33 33 */ 34 34 … … 40 40 #include <stdint.h> 41 41 42 #include " hdaudio_regs.h"42 #include "spec/regs.h" 43 43 44 /** High Definition Audio Controller*/44 /** High Definition Audio driver instance */ 45 45 typedef struct { 46 46 async_sess_t *parent_sess; -
uspace/drv/audio/hdaudio/hdaudio.ma
rb229062 r7978d1e7 1 10 pci/ven=1002&dev=4383 1 2 10 pci/ven=8086&dev=2668 -
uspace/drv/audio/hdaudio/spec/regs.h
rb229062 r7978d1e7 33 33 */ 34 34 35 #ifndef HDAUDIO_REGS_H36 #define HDAUDIO_REGS_H35 #ifndef SPEC_REGS_H 36 #define SPEC_REGS_H 37 37 38 38 #include <sys/types.h> … … 100 100 uint32_t walclk; 101 101 /** Reserved */ 102 uint32_t reserved4[4]; 102 uint8_t reserved4[4]; 103 /** Stream Synchronization */ 104 uint32_t ssync; 105 /** Reserved */ 106 uint8_t reserved5[4]; 103 107 /** CORB Lower Base Address */ 104 108 uint32_t corblbase; … … 116 120 uint8_t corbsize; 117 121 /** Reserved */ 118 uint8_t reserved 5[1];122 uint8_t reserved6[1]; 119 123 /** RIRB Lower Base Address */ 120 124 uint32_t rirblbase; … … 132 136 uint8_t rirbsize; 133 137 /** Reserved */ 134 uint8_t reserved 6[1];138 uint8_t reserved7[1]; 135 139 /** Immediate Command Output Interface */ 136 140 uint32_t icoi; … … 140 144 uint32_t icis; 141 145 /** Reserved */ 142 uint8_t reserved 7[6];146 uint8_t reserved8[6]; 143 147 /** DMA Position Buffer Lower Base */ 144 148 uint32_t dpiblbase; … … 146 150 uint32_t dpibubase; 147 151 /** Reserved */ 148 uint8_t reserved 8[8];152 uint8_t reserved9[8]; 149 153 /** Stream descriptor registers */ 150 154 hda_sdesc_regs_t sdesc[64]; 151 155 /** Fill up to 0x2030 */ 152 uint8_t reserved 9[6064];156 uint8_t reserved10[6064]; 153 157 /** Wall Clock Counter Alias */ 154 158 uint32_t walclka; … … 157 161 } hda_regs_t; 158 162 163 typedef enum { 164 /** Number of Output Streams Supported (H) */ 165 gcap_oss_h = 15, 166 /** Number of Output Streams Supported (L) */ 167 gcap_oss_l = 12, 168 /** Number of Input Streams Supported (H) */ 169 gcap_iss_h = 11, 170 /** Number of Input Streams Supported (L) */ 171 gcap_iss_l = 8, 172 /** Number of Bidirectional Streams Supported (H) */ 173 gcap_bss_h = 7, 174 /** Number of Bidirectional Streams Supported (L) */ 175 gcap_bss_l = 3, 176 /** Number of Serial Data Out Signals (H) */ 177 gcap_nsdo_h = 2, 178 /** Number of Serial Data Out Signals (H) */ 179 gcap_nsdo_l = 1, 180 /** 64 Bit Address Supported */ 181 gcap_64ok = 0 182 } hda_gcap_bits_t; 183 184 typedef enum { 185 /** Accept Unsolicited Response Enable */ 186 gctl_unsol = 8, 187 /** Flush Control */ 188 gctl_fcntrl = 1, 189 /** Controller Reset */ 190 gctl_crst = 0 191 } hda_gctl_bits_t; 192 193 typedef enum { 194 /** CORB Read Pointer Reset */ 195 corbrp_rst = 15, 196 /** CORB Read Pointer (H) */ 197 corbrp_rp_h = 7, 198 /** CORB Read Pointer (L) */ 199 corbrp_rp_l = 0 200 } hda_corbrp_bits_t; 201 202 typedef enum { 203 /** Enable CORB DMA Engine */ 204 corbctl_run = 1, 205 /** CORB Memory Error Interrupt Enable */ 206 corbctl_meie = 0 207 } hda_corbctl_bits_t; 208 209 typedef enum { 210 /** CORB Size Capability (H) */ 211 corbsize_cap_h = 7, 212 /** CORB Size Capability (L) */ 213 corbsize_cap_l = 4, 214 /** CORB Size (H) */ 215 corbsize_size_h = 1, 216 /** CORB Size (L) */ 217 corbsize_size_l = 0 218 } hda_corbsize_bits_t; 219 220 typedef enum { 221 /** RIRB Write Pointer Reset */ 222 rirbwp_rst = 15, 223 /** RIRB Write Pointer (H) */ 224 rirbwp_wp_h = 7, 225 /** RIRB Write Pointer (L) */ 226 rirbrp_wp_l = 0 227 } hda_rirbwp_bits_t; 228 229 typedef enum { 230 /** Response Overrun Interrupt Control */ 231 rirbctl_oic = 2, 232 /** RIRB DMA Enable */ 233 rirbctl_run = 1, 234 /** CORB Memory Error Interrupt Enable */ 235 rirbctl_int = 0 236 } hda_rirbctl_bits_t; 237 238 typedef enum { 239 /** RIRB Size Capability (H) */ 240 rirbsize_cap_h = 7, 241 /** RIRB Size Capability (L) */ 242 rirbsize_cap_l = 4, 243 /** RIRB Size (H) */ 244 rirbsize_size_h = 1, 245 /** RIRB Size (L) */ 246 rirbsize_size_l = 0 247 } hda_rirbsize_bits_t; 248 159 249 #endif 160 250
Note:
See TracChangeset
for help on using the changeset viewer.