blob: efbd542974c9f8c59667d8cdad58b95ccb26c11f [file] [log] [blame]
#!/usr/bin/env python3
#
# Copyright (c) 2019 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
import math
import logging
from time import sleep
from ctypes import c_uint16, POINTER, cast, c_uint8, c_uint64
from lib.driver import Register
import lib.registers as regs_def
import lib.platforms as plat_def
class DmaBuf:
""" Class for DMA buffer """
def __init__(self, drv, size):
self.drv = drv
self.size = size
# Allocated DMA buffer should be a multiplication of page size
self.page_count = math.ceil(self.size / plat_def.DMA_PAGE_SIZE)
logging.debug("Page Count: %d" % self.page_count)
self.alloc_size = self.page_count * plat_def.DMA_PAGE_SIZE
logging.debug("Allocate DMA Buffer: size=0x%08X alloc_size=0x%08X"
% (self.size, self.alloc_size))
self.mem = self.drv.alloc_mem(self.alloc_size)
self.addr_p = self.mem.dma_addr_p
self.buf = cast(self.mem.dma_addr_v,
POINTER(c_uint8 * self.alloc_size)).contents
def copy(self, data, size):
""" Copying data to allocated DMA buffer """
if size > self.alloc_size:
raise ValueError("Not enough buffer. allocated: %d requested: %d"
% (self.alloc_size, size))
logging.debug("Copying Data to DMA buffer")
self.buf[:size] = data[:size]
def free(self):
if self.mem:
self.drv.free_mem(self.mem)
self.mem = None
class DmaBufDescList:
""" Class DMA Buffer Descriptor List """
def __init__(self, drv, fw_buf):
self.drv = drv
self.bd_count = fw_buf.page_count
# Single Page for Buffer Descriptor List
self.buf = DmaBuf(drv, plat_def.DMA_PAGE_SIZE)
curr_ptr = 0
# Map BDLE with data buffer
logging.debug("Update Buffer Descriptor List:")
for i in range(self.bd_count):
bdle_addr = Register(self.buf.mem.memmap, (i * 16) + 0x00, c_uint64)
bdle_len = Register(self.buf.mem.memmap, (i * 16) + 0x08)
bdle_ioc = Register(self.buf.mem.memmap, (i * 16) + 0x0C)
if fw_buf.alloc_size - curr_ptr > plat_def.DMA_PAGE_SIZE:
bdle_len.value = plat_def.DMA_PAGE_SIZE
bdle_ioc.value = 0
bdle_addr.value = fw_buf.addr_p + curr_ptr
else:
bdle_len.value = fw_buf.alloc_size - curr_ptr
bdle_ioc.value = 1
bdle_addr.value = fw_buf.addr_p + curr_ptr
logging.debug(" BDLE#%02d: ADDR: %s LEN: %s IOC: %s"
% (i, bdle_addr, bdle_len, bdle_ioc))
break
curr_ptr += plat_def.DMA_PAGE_SIZE
logging.debug(" BDLE#%02d: ADDR: %s LEN: %s IOC: %s"
% (i, bdle_addr, bdle_len, bdle_ioc))
def free(self):
if self.buf:
self.drv.free_mem(self.buf.mem)
self.buf = None
class StreamDesc:
""" Class for Stream Descriptor """
def __init__(self, idx, dev):
self.idx = idx
self.dev = dev
self.used = False
self.buf = None
self.bdl = None
offset = regs_def.HDA_SD_BASE + (regs_def.HDA_SD_SIZE * (idx))
# Registers in SD
self.ctl_sts = Register(self.dev.hda_bar_mmap,
offset + regs_def.HDA_SD_CS)
self.lpib = Register(self.dev.hda_bar_mmap,
offset + regs_def.HDA_SD_LPIB)
self.cbl = Register(self.dev.hda_bar_mmap,
offset + regs_def.HDA_SD_CBL)
self.lvi = Register(self.dev.hda_bar_mmap,
offset + regs_def.HDA_SD_LVI, c_uint16)
self.fifow = Register(self.dev.hda_bar_mmap,
offset + regs_def.HDA_SD_FIFOW, c_uint16)
self.fifos = Register(self.dev.hda_bar_mmap,
offset + regs_def.HDA_SD_FIFOS, c_uint16)
self.fmt = Register(self.dev.hda_bar_mmap,
offset + regs_def.HDA_SD_FMT, c_uint16)
self.fifol = Register(self.dev.hda_bar_mmap,
offset + regs_def.HDA_SD_FIFOL)
self.bdlplba = Register(self.dev.hda_bar_mmap,
offset + regs_def.HDA_SD_BDLPLBA)
self.bdlpuba = Register(self.dev.hda_bar_mmap,
offset + regs_def.HDA_SD_BDLPUBA)
# Register for SPIB
offset = regs_def.HDA_SPBF_SD_BASE + (regs_def.HDA_SPBF_SD_SIZE * (idx))
self.sdspib = Register(self.dev.hda_bar_mmap,
offset + regs_def.HDA_SPBF_SDSPIB)
def free_memory(self):
if self.buf is not None:
self.buf.free()
self.buf = None
if self.bdl is not None:
self.bdl.free()
self.bdl = None
def alloc_memory(self, size):
self.free_memory()
self.buf = DmaBuf(self.dev.drv, size)
self.bdl = DmaBufDescList(self.dev.drv, self.buf)
def config(self):
self.bdlplba.value = self.bdl.buf.addr_p & 0xFFFFFFFF
self.bdlpuba.value = self.bdl.buf.addr_p >> 32
self.cbl.value = self.buf.size
self.lvi.value = self.bdl.bd_count - 1
self.sdspib.value = self.cbl.value
def set_bitrate(self, bit_rate):
logging.debug("SD#%02d: Set Bitrate: 0x%04X" % (self.idx, bit_rate))
sdfmt = self.fmt.value
sdfmt |= (bit_rate << 4)
self.fmt.value = sdfmt
logging.debug("SD#%02d: SD_FMT=%s" % (self.idx, self.fmt))
def set_stream_id(self, stream_id):
logging.debug("SD#%02d: Set Stream ID: 0x%04X" % (self.idx, stream_id))
sd_ctl = self.ctl_sts.value
sd_ctl &= ~(0xF << 20)
sd_ctl |= (stream_id << 20)
self.ctl_sts.value = sd_ctl
logging.debug("SD#%02d: SD_CTL_STS=%s" % (self.idx, self.ctl_sts))
def set_traffic_priority(self, value):
logging.debug("SD#%02d: Set Traffic Priority(0x%02X)" % (self.idx, value))
sd_ctl = self.ctl_sts.value
sd_ctl |= (value << 18)
self.ctl_sts.value = sd_ctl
logging.debug("SD#%02d: SD_CTL_STS=%s" % (self.idx, self.ctl_sts))
def start(self):
""" Start DMA transfer """
logging.debug("SD#%02d: Start DMA stream" % self.idx)
self.ctl_sts.value = self.ctl_sts.value | (1 << 1)
logging.debug("SD#%02d: SD_CTL_STS=%s" % (self.idx, self.ctl_sts))
while self.ctl_sts.value & (1 << 1) == 0:
sleep(0.001)
def pause(self):
logging.debug("SD#%02d: Pause DMA stream" % self.idx)
self.ctl_sts.value = self.ctl_sts.value & ~(1 << 1)
while self.ctl_sts.value & (1 << 1):
sleep(0.001)
def reset(self):
logging.debug("SD#%02d: Reset DAM stream" % self.idx)
self.pause()
self.ctl_sts.value = self.ctl_sts.value | 1
sleep(0.01)
self.ctl_sts.value = self.ctl_sts.value & ~1
sleep(0.01)
class StreamDescList:
""" Class for DMA Stream Descriptor List """
def __init__(self, dev):
self.dev = dev
self.sdl = []
for i in range(plat_def.NUM_STREAMS):
sd = StreamDesc(i, self.dev)
self.sdl.append(sd)
def close(self):
for sd in self.sdl:
if sd.used:
self.release(sd)
def reset_all(self):
for sd in self.sdl:
sd.reset()
def get_sd(self, idx):
sd = self.sdl[idx]
if sd.used:
raise ResourceWarning("IOB #%d already in use!" % idx)
sd.used = True
return sd
def release(self, sd):
return self.release_sd(sd.idx)
def release_sd(self, idx, reset_hw=True):
if not self.sdl[idx].used:
logging.warning("SD#%d: Not used!!!" % idx)
self.sdl[idx].used = False
if reset_hw:
self.sdl[idx].pause()
self.sdl[idx].reset()
self.sdl[idx].free_memory()