1#!/usr/bin/env python3 2# 3# Copyright (c) 2019 Intel Corporation 4# 5# SPDX-License-Identifier: Apache-2.0 6import math 7import logging 8from time import sleep 9from ctypes import c_uint16, POINTER, cast, c_uint8, c_uint64 10 11from lib.driver import Register 12import lib.registers as regs_def 13import lib.platforms as plat_def 14 15 16class DmaBuf: 17 """ Class for DMA buffer """ 18 19 def __init__(self, drv, size): 20 self.drv = drv 21 self.size = size 22 23 # Allocated DMA buffer should be a multiplication of page size 24 self.page_count = math.ceil(self.size / plat_def.DMA_PAGE_SIZE) 25 logging.debug("Page Count: %d" % self.page_count) 26 27 self.alloc_size = self.page_count * plat_def.DMA_PAGE_SIZE 28 logging.debug("Allocate DMA Buffer: size=0x%08X alloc_size=0x%08X" 29 % (self.size, self.alloc_size)) 30 self.mem = self.drv.alloc_mem(self.alloc_size) 31 self.addr_p = self.mem.dma_addr_p 32 self.buf = cast(self.mem.dma_addr_v, 33 POINTER(c_uint8 * self.alloc_size)).contents 34 35 def copy(self, data, size): 36 """ Copying data to allocated DMA buffer """ 37 if size > self.alloc_size: 38 raise ValueError("Not enough buffer. allocated: %d requested: %d" 39 % (self.alloc_size, size)) 40 logging.debug("Copying Data to DMA buffer") 41 self.buf[:size] = data[:size] 42 43 def free(self): 44 if self.mem: 45 self.drv.free_mem(self.mem) 46 self.mem = None 47 48 49class DmaBufDescList: 50 """ Class DMA Buffer Descriptor List """ 51 52 def __init__(self, drv, fw_buf): 53 self.drv = drv 54 self.bd_count = fw_buf.page_count 55 56 # Single Page for Buffer Descriptor List 57 self.buf = DmaBuf(drv, plat_def.DMA_PAGE_SIZE) 58 59 curr_ptr = 0 60 # Map BDLE with data buffer 61 logging.debug("Update Buffer Descriptor List:") 62 for i in range(self.bd_count): 63 bdle_addr = Register(self.buf.mem.memmap, (i * 16) + 0x00, c_uint64) 64 bdle_len = Register(self.buf.mem.memmap, (i * 16) + 0x08) 65 bdle_ioc = Register(self.buf.mem.memmap, (i * 16) + 0x0C) 66 67 if fw_buf.alloc_size - curr_ptr > plat_def.DMA_PAGE_SIZE: 68 bdle_len.value = plat_def.DMA_PAGE_SIZE 69 bdle_ioc.value = 0 70 bdle_addr.value = fw_buf.addr_p + curr_ptr 71 else: 72 bdle_len.value = fw_buf.alloc_size - curr_ptr 73 bdle_ioc.value = 1 74 bdle_addr.value = fw_buf.addr_p + curr_ptr 75 76 logging.debug(" BDLE#%02d: ADDR: %s LEN: %s IOC: %s" 77 % (i, bdle_addr, bdle_len, bdle_ioc)) 78 break 79 curr_ptr += plat_def.DMA_PAGE_SIZE 80 logging.debug(" BDLE#%02d: ADDR: %s LEN: %s IOC: %s" 81 % (i, bdle_addr, bdle_len, bdle_ioc)) 82 83 def free(self): 84 if self.buf: 85 self.drv.free_mem(self.buf.mem) 86 self.buf = None 87 88 89class StreamDesc: 90 """ Class for Stream Descriptor """ 91 92 def __init__(self, idx, dev): 93 self.idx = idx 94 self.dev = dev 95 self.used = False 96 self.buf = None 97 self.bdl = None 98 99 offset = regs_def.HDA_SD_BASE + (regs_def.HDA_SD_SIZE * (idx)) 100 # Registers in SD 101 self.ctl_sts = Register(self.dev.hda_bar_mmap, 102 offset + regs_def.HDA_SD_CS) 103 self.lpib = Register(self.dev.hda_bar_mmap, 104 offset + regs_def.HDA_SD_LPIB) 105 self.cbl = Register(self.dev.hda_bar_mmap, 106 offset + regs_def.HDA_SD_CBL) 107 self.lvi = Register(self.dev.hda_bar_mmap, 108 offset + regs_def.HDA_SD_LVI, c_uint16) 109 self.fifow = Register(self.dev.hda_bar_mmap, 110 offset + regs_def.HDA_SD_FIFOW, c_uint16) 111 self.fifos = Register(self.dev.hda_bar_mmap, 112 offset + regs_def.HDA_SD_FIFOS, c_uint16) 113 self.fmt = Register(self.dev.hda_bar_mmap, 114 offset + regs_def.HDA_SD_FMT, c_uint16) 115 self.fifol = Register(self.dev.hda_bar_mmap, 116 offset + regs_def.HDA_SD_FIFOL) 117 self.bdlplba = Register(self.dev.hda_bar_mmap, 118 offset + regs_def.HDA_SD_BDLPLBA) 119 self.bdlpuba = Register(self.dev.hda_bar_mmap, 120 offset + regs_def.HDA_SD_BDLPUBA) 121 122 # Register for SPIB 123 offset = regs_def.HDA_SPBF_SD_BASE + (regs_def.HDA_SPBF_SD_SIZE * (idx)) 124 self.sdspib = Register(self.dev.hda_bar_mmap, 125 offset + regs_def.HDA_SPBF_SDSPIB) 126 127 def free_memory(self): 128 if self.buf is not None: 129 self.buf.free() 130 self.buf = None 131 if self.bdl is not None: 132 self.bdl.free() 133 self.bdl = None 134 135 def alloc_memory(self, size): 136 self.free_memory() 137 self.buf = DmaBuf(self.dev.drv, size) 138 self.bdl = DmaBufDescList(self.dev.drv, self.buf) 139 140 def config(self): 141 self.bdlplba.value = self.bdl.buf.addr_p & 0xFFFFFFFF 142 self.bdlpuba.value = self.bdl.buf.addr_p >> 32 143 self.cbl.value = self.buf.size 144 self.lvi.value = self.bdl.bd_count - 1 145 self.sdspib.value = self.cbl.value 146 147 def set_bitrate(self, bit_rate): 148 logging.debug("SD#%02d: Set Bitrate: 0x%04X" % (self.idx, bit_rate)) 149 sdfmt = self.fmt.value 150 sdfmt |= (bit_rate << 4) 151 self.fmt.value = sdfmt 152 logging.debug("SD#%02d: SD_FMT=%s" % (self.idx, self.fmt)) 153 154 def set_stream_id(self, stream_id): 155 logging.debug("SD#%02d: Set Stream ID: 0x%04X" % (self.idx, stream_id)) 156 sd_ctl = self.ctl_sts.value 157 sd_ctl &= ~(0xF << 20) 158 sd_ctl |= (stream_id << 20) 159 self.ctl_sts.value = sd_ctl 160 logging.debug("SD#%02d: SD_CTL_STS=%s" % (self.idx, self.ctl_sts)) 161 162 def set_traffic_priority(self, value): 163 logging.debug("SD#%02d: Set Traffic Priority(0x%02X)" % (self.idx, value)) 164 sd_ctl = self.ctl_sts.value 165 sd_ctl |= (value << 18) 166 self.ctl_sts.value = sd_ctl 167 logging.debug("SD#%02d: SD_CTL_STS=%s" % (self.idx, self.ctl_sts)) 168 169 def start(self): 170 """ Start DMA transfer """ 171 logging.debug("SD#%02d: Start DMA stream" % self.idx) 172 self.ctl_sts.value = self.ctl_sts.value | (1 << 1) 173 logging.debug("SD#%02d: SD_CTL_STS=%s" % (self.idx, self.ctl_sts)) 174 while self.ctl_sts.value & (1 << 1) == 0: 175 sleep(0.001) 176 177 def pause(self): 178 logging.debug("SD#%02d: Pause DMA stream" % self.idx) 179 self.ctl_sts.value = self.ctl_sts.value & ~(1 << 1) 180 while self.ctl_sts.value & (1 << 1): 181 sleep(0.001) 182 183 def reset(self): 184 logging.debug("SD#%02d: Reset DAM stream" % self.idx) 185 self.pause() 186 self.ctl_sts.value = self.ctl_sts.value | 1 187 sleep(0.01) 188 self.ctl_sts.value = self.ctl_sts.value & ~1 189 sleep(0.01) 190 191 192class StreamDescList: 193 """ Class for DMA Stream Descriptor List """ 194 195 def __init__(self, dev): 196 self.dev = dev 197 self.sdl = [] 198 for i in range(plat_def.NUM_STREAMS): 199 sd = StreamDesc(i, self.dev) 200 self.sdl.append(sd) 201 202 def close(self): 203 for sd in self.sdl: 204 if sd.used: 205 self.release(sd) 206 207 def reset_all(self): 208 for sd in self.sdl: 209 sd.reset() 210 211 def get_sd(self, idx): 212 sd = self.sdl[idx] 213 if sd.used: 214 raise ResourceWarning("IOB #%d already in use!" % idx) 215 sd.used = True 216 return sd 217 218 def release(self, sd): 219 return self.release_sd(sd.idx) 220 221 def release_sd(self, idx, reset_hw=True): 222 if not self.sdl[idx].used: 223 logging.warning("SD#%d: Not used!!!" % idx) 224 self.sdl[idx].used = False 225 if reset_hw: 226 self.sdl[idx].pause() 227 self.sdl[idx].reset() 228 self.sdl[idx].free_memory() 229