audio_4231_apcdma.c revision 11936:54dc8a89ba0d
1279377Simp/* 2279377Simp * CDDL HEADER START 3279377Simp * 4279377Simp * The contents of this file are subject to the terms of the 5279377Simp * Common Development and Distribution License (the "License"). 6279377Simp * You may not use this file except in compliance with the License. 7279377Simp * 8279377Simp * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9279377Simp * or http://www.opensolaris.org/os/licensing. 10279377Simp * See the License for the specific language governing permissions 11279377Simp * and limitations under the License. 12279377Simp * 13279377Simp * When distributing Covered Code, include this CDDL HEADER in each 14279377Simp * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15279377Simp * If applicable, add the following below this CDDL HEADER, with the 16279377Simp * fields enclosed by brackets "[]" replaced with your own identifying 17279377Simp * information: Portions Copyright [yyyy] [name of copyright owner] 18279377Simp * 19279377Simp * CDDL HEADER END 20279377Simp */ 21279377Simp/* 22279377Simp * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23279377Simp * Use is subject to license terms. 24279377Simp */ 25279377Simp 26279377Simp/* 27279377Simp * Platform specifc code for the APC DMA controller. The APC is an SBus 28279377Simp * IC that includes play and record DMA engines and an interface for 29279377Simp * the CS4231. 30279377Simp */ 31279377Simp 32279377Simp#include <sys/systm.h> 33279377Simp#include <sys/ddi.h> 34279377Simp#include <sys/sunddi.h> 35279377Simp#include <sys/note.h> 36279377Simp#include <sys/audio/audio_driver.h> 37279377Simp#include "audio_4231.h" 38279377Simp 39279377Simp/* 40279377Simp * Attribute structure for the APC, used to create DMA handles. 41279377Simp */ 42279377Simpstatic ddi_dma_attr_t apc_dma_attr = { 43279377Simp DMA_ATTR_V0, /* version */ 44279377Simp 0x0000000000000000LL, /* dlim_addr_lo */ 45279377Simp 0x00000000ffffffffLL, /* dlim_addr_hi */ 46279377Simp 0x0000000000000fffLL, /* DMA counter register */ 47279377Simp 0x0000000000000001LL, /* DMA address alignment */ 48279377Simp 0x00000014, /* 4 and 16 byte burst sizes */ 49279377Simp 0x00000001, /* min effective DMA size */ 50279377Simp 0x0000000000000fffLL, /* maximum transfer size, 8k */ 51279377Simp 0x000000000000ffffLL, /* segment boundary, 32k */ 52279377Simp 0x00000001, /* s/g list length, no s/g */ 53279377Simp 0x00000001, /* granularity of device, don't care */ 54279377Simp 0 /* DMA flags */ 55279377Simp}; 56279377Simp 57279377Simpstatic ddi_device_acc_attr_t acc_attr = { 58279377Simp DDI_DEVICE_ATTR_V0, 59279377Simp DDI_STRUCTURE_BE_ACC, 60279377Simp DDI_STRICTORDER_ACC 61279377Simp}; 62279377Simp 63279377Simp/* 64279377Simp * DMA ops vector functions 65279377Simp */ 66279377Simpstatic int apc_map_regs(CS_state_t *); 67279377Simpstatic void apc_unmap_regs(CS_state_t *); 68279377Simpstatic void apc_reset(CS_state_t *); 69279377Simpstatic int apc_start_engine(CS_engine_t *); 70279377Simpstatic void apc_stop_engine(CS_engine_t *); 71279377Simpstatic void apc_power(CS_state_t *, int); 72279377Simpstatic void apc_reload(CS_engine_t *); 73279377Simpstatic uint32_t apc_addr(CS_engine_t *); 74279377Simp 75279377Simpcs4231_dma_ops_t cs4231_apcdma_ops = { 76279377Simp "APC DMA controller", 77279377Simp &apc_dma_attr, 78279377Simp apc_map_regs, 79279377Simp apc_unmap_regs, 80279377Simp apc_reset, 81279377Simp apc_start_engine, 82279377Simp apc_stop_engine, 83279377Simp apc_power, 84279377Simp apc_reload, 85279377Simp apc_addr, 86279377Simp}; 87279377Simp 88279377Simp/* 89279377Simp * apc_map_regs() 90279377Simp * 91279377Simp * Description: 92279377Simp * This routine allocates the DMA handles and the memory for the 93279377Simp * DMA engines to use. It then binds each of the buffers to its 94279377Simp * respective handle, getting a DMA cookie. Finally, the registers 95279377Simp * are mapped in. 96279377Simp * 97279377Simp * NOTE: All of the ddi_dma_... routines sleep if they cannot get 98 * memory. This means these calls will almost always succeed. 99 * 100 * Arguments: 101 * CS_state_t *state The device's state structure 102 * 103 * Returns: 104 * AUDIO_SUCCESS Registers successfully mapped 105 * AUDIO_FAILURE Registers not successfully mapped 106 */ 107static int 108apc_map_regs(CS_state_t *state) 109{ 110 ddi_acc_handle_t *handle = &APC_HANDLE; 111 dev_info_t *dip = state->cs_dip; 112 113 /* map in the registers, getting a handle */ 114 if (ddi_regs_map_setup(dip, 0, (caddr_t *)&state->cs_regs, 0, 115 sizeof (cs4231_regs_t), &acc_attr, handle) != DDI_SUCCESS) { 116 audio_dev_warn(state->cs_adev, "ddi_regs_map_setup() failed"); 117 return (DDI_FAILURE); 118 } 119 120 /* clear the CSR so we have all interrupts disabled */ 121 ddi_put32(*handle, &APC_DMACSR, APC_CLEAR_RESET_VALUE); 122 123 return (DDI_SUCCESS); 124} /* apc_map_regs() */ 125 126/* 127 * apc_unmap_regs() 128 * 129 * Description: 130 * This routine unmaps the Codec's and DMA engine's registers. 131 * It must be idempotent. 132 * 133 * Arguments: 134 * CS_state_t *state The device's state structure 135 * 136 * Returns: 137 * void 138 */ 139static void 140apc_unmap_regs(CS_state_t *state) 141{ 142 if (APC_HANDLE) 143 ddi_regs_map_free(&APC_HANDLE); 144 145} /* apc_unmap_regs() */ 146 147/* 148 * apc_reset() 149 * 150 * Description: 151 * Reset both the play and record DMA engines. The engines are left 152 * with interrupts and the DMA engine disabled. 153 * 154 * Arguments: 155 * dev_info_t *dip Pointer to the device's devinfo structure 156 * CS_state_t *state The device's state structure 157 * 158 * Returns: 159 * void 160 */ 161static void 162apc_reset(CS_state_t *state) 163{ 164 ddi_acc_handle_t handle = APC_HANDLE; 165 166 /* 167 * The APC has a bug where the reset is not done 168 * until you do the next pio to the APC. This 169 * next write to the CSR causes the posted reset to 170 * happen. 171 */ 172 173 ddi_put32(handle, &APC_DMACSR, APC_RESET); 174 ddi_put32(handle, &APC_DMACSR, APC_CLEAR_RESET_VALUE); 175 176} /* apc_reset() */ 177 178/* 179 * apc_start_engine() 180 * 181 * Description: 182 * This routine starts the DMA engine. 183 * 184 * For hard starts the DMA engine is started by programming the 185 * Next Virtual Address and then the Next Counter twice, and 186 * finally enabling the DMA engine. 187 * 188 * NOTE: The state structure must be locked before this routine is called. 189 * 190 * CAUTION: ?!? This routine doesn't start the Codec because the first 191 * interrupt causes a recursive mutex_enter. 192 * 193 * Arguments: 194 * CS_engine_t *eng The engine to start 195 * 196 * Returns: 197 * DDI_SUCCESS The DMA engine was started 198 * DDI_FAILURE The DMA engine was not started 199 */ 200static int 201apc_start_engine(CS_engine_t *eng) 202{ 203 CS_state_t *state = eng->ce_state; 204 ddi_acc_handle_t handle = APC_HANDLE; 205 uint32_t csr; 206 uint32_t enable; 207 uint32_t dirty; 208 int x; 209 210 ASSERT(mutex_owned(&state->cs_lock)); 211 212 if (eng->ce_num == CS4231_PLAY) { 213 enable = APC_PDMA_GO; 214 dirty = APC_PD; 215 } else { 216 enable = APC_CDMA_GO; 217 dirty = APC_CD; 218 } 219 220 /* make sure it's okay to program the Next Address/Count registers */ 221 csr = ddi_get32(handle, &APC_DMACSR); 222 for (x = 0; !(csr & dirty) && x < CS4231_TIMEOUT; x++) { 223 drv_usecwait(1); /* no reason to beat on the bus */ 224 csr = ddi_get32(handle, &APC_DMACSR); 225 } 226 if (x >= CS4231_TIMEOUT) { 227 audio_dev_warn(state->cs_adev, 228 "timeout waiting for engine, not started!"); 229 return (DDI_FAILURE); 230 } 231 232 /* 233 * Program the first fragment. 234 */ 235 apc_reload(eng); 236 237 /* 238 * Start the DMA engine, including interrupts. 239 */ 240 OR_SET_WORD(handle, &APC_DMACSR, enable); 241 242 /* 243 * Program the double buffering. 244 */ 245 apc_reload(eng); 246 247 return (DDI_SUCCESS); 248} 249 250/* 251 * apc_stop_engine() 252 * 253 * Description: 254 * This routine stops the engine. 255 * 256 * The DMA engine is stopped by using the CAP_ABORT bit. 257 * 258 * NOTE: The state structure must be locked before this routine is called. 259 * 260 * Arguments: 261 * CS_engine_t *eng The engine to sotp 262 * 263 * Returns: 264 * void 265 */ 266static void 267apc_stop_engine(CS_engine_t *eng) 268{ 269 CS_state_t *state = eng->ce_state; 270 ddi_acc_handle_t handle = APC_HANDLE; 271 uint32_t reg; 272 uint32_t abort; 273 uint32_t drainbit; 274 uint32_t disable; 275 276 ASSERT(mutex_owned(&state->cs_lock)); 277 278 if (eng->ce_num == CS4231_PLAY) { 279 abort = APC_P_ABORT; 280 drainbit = APC_PM; 281 disable = APC_PLAY_DISABLE; 282 } else { 283 abort = APC_C_ABORT; 284 drainbit = APC_CX; 285 disable = APC_CAP_DISABLE; 286 } 287 288 /* first, abort the DMA engine */ 289 OR_SET_WORD(handle, &APC_DMACSR, abort); 290 291 /* wait for the pipeline to empty */ 292 reg = ddi_get32(handle, &APC_DMACSR); 293 for (int x = 0; (!(reg & drainbit)) && (x < CS4231_TIMEOUT); x++) { 294 drv_usecwait(1); /* don't beat on bus */ 295 reg = ddi_get32(handle, &APC_DMACSR); 296 } 297 298 /* now clear the enable and abort bits */ 299 AND_SET_WORD(handle, &APC_DMACSR, ~(abort|disable)); 300} 301 302 303/* 304 * apc_power() 305 * 306 * Description: 307 * This routine turns the Codec off by using the COD_PDWN bit in the 308 * apc chip. To turn power on we have to reset the APC, which clears 309 * the COD_PDWN bit. However, this is a settling bug in the APC which 310 * requires the driver to delay quite a while before we may continue. 311 * Since this is the first time this feature has actually been used 312 * it isn't too surprising that it has some problems. 313 * 314 * NOTE: The state structure must be locked when this routine is called. 315 * 316 * Arguments: 317 * CS_state_t *state Ptr to the device's state structure 318 * int level Power level to set 319 */ 320static void 321apc_power(CS_state_t *state, int level) 322{ 323 ddi_acc_handle_t handle = APC_HANDLE; 324 325 if (level == CS4231_PWR_ON) { /* turn power on */ 326 AND_SET_WORD(handle, &APC_DMACSR, ~APC_COD_PDWN); 327 OR_SET_WORD(handle, &APC_DMACSR, APC_RESET); 328 AND_SET_WORD(handle, &APC_DMACSR, ~APC_RESET); 329 330 /* 331 * wait for state change, 332 */ 333 delay(drv_usectohz(CS4231_300MS)); 334 } else { /* turn power off */ 335 ASSERT(level == CS4231_PWR_OFF); 336 OR_SET_WORD(handle, &APC_DMACSR, APC_COD_PDWN); 337 } 338 339} /* apc_power() */ 340 341 342static void 343apc_reload(CS_engine_t *eng) 344{ 345 CS_state_t *state = eng->ce_state; 346 ddi_acc_handle_t handle = APC_HANDLE; 347 uint32_t dirty; 348 uint32_t *nva; /* next VA reg */ 349 uint32_t *nc; /* next count reg */ 350 351 if (eng->ce_num == CS4231_PLAY) { 352 dirty = APC_PD; 353 nva = &APC_DMAPNVA; 354 nc = &APC_DMAPNC; 355 } else { 356 dirty = APC_CD; 357 nva = &APC_DMACNVA; 358 nc = &APC_DMACNC; 359 } 360 361 /* if we can't load another address, then don't */ 362 if ((ddi_get32(handle, &APC_DMACSR) & dirty) == 0) { 363 return; 364 } 365 366 /* read the NVA, as per APC document */ 367 (void) ddi_get32(handle, nva); 368 369 /* write the address of the next fragment */ 370 ddi_put32(handle, nva, 371 eng->ce_paddr + (CS4231_FRAGSZ * eng->ce_curidx)); 372 eng->ce_curidx++; 373 eng->ce_curidx %= CS4231_NFRAGS; 374 375 /* now program the NC reg., which enables the state machine */ 376 ddi_put32(handle, nc, CS4231_FRAGSZ); 377} 378 379/* 380 * apc_addr() 381 * 382 * Description: 383 * This routine returns the current DMA address for the engine (the 384 * next address being accessed). 385 * 386 * Arguments: 387 * CS_engine_t *eng The engine 388 * 389 * Returns: 390 * Physical DMA address for current transfer. 391 */ 392static uint32_t 393apc_addr(CS_engine_t *eng) 394{ 395 CS_state_t *state = eng->ce_state; 396 ddi_acc_handle_t handle = APC_HANDLE; 397 uint32_t *va; /* VA reg */ 398 399 if (eng->ce_num == CS4231_PLAY) { 400 va = &APC_DMAPVA; 401 } else { 402 va = &APC_DMACVA; 403 } 404 405 return (ddi_get32(handle, va)); 406} 407