1#!/usr/bin/env python3
2#
3# Copyright (c) 2019 Intel Corporation
4#
5# SPDX-License-Identifier: Apache-2.0
6import time
7import logging
8from ctypes import  c_uint16, addressof
9
10from lib.driver import DiagDriver, Register
11import lib.registers as regs_def
12import lib.platforms as plat_def
13
14
15class Device:
16
17    def __init__(self):
18        self.__opened = False
19
20        self.drv = DiagDriver()
21        self.dev_info = None
22
23        self.hda_bar_mmap = None
24        self.dsp_bar_mmap = None
25
26        self.hda_gctl = None
27        self.hda_gcap = None
28        self.hda_ppctl = None
29        self.hda_spibe = None
30
31        self.dsp_ctl_sts = None
32        self.dsp_hipci = None
33        self.dsp_hipcie = None
34        self.dsp_hipct = None
35
36        self.fw_status = None
37        self.fw_err_code = None
38
39        self.ipc_len = None
40        self.ipc_cmd = None
41
42        self.allocated = []
43
44    def close(self):
45        if not self.__opened:
46            logging.warning("Audio device not opened!!!")
47            return
48        self.__opened = False
49
50    def open_device(self):
51        logging.debug(">>> Device.open_device()")
52
53        # Open device to get HDA BAR and DSP BAR
54        self.dev_info = self.drv.open_device()
55
56        # HDA MMAP
57        self.hda_bar_mmap = self.drv.mmap(self.dev_info.hda_bar.base_p,
58                                          self.dev_info.hda_bar.size)
59        self.dev_info.hda_bar.base_v = addressof(self.hda_bar_mmap)
60        # DSP MMAP
61        self.dsp_bar_mmap = self.drv.mmap(self.dev_info.dsp_bar.base_p,
62                                          self.dev_info.dsp_bar.size)
63        self.dev_info.dsp_bar.base_v = addressof(self.dsp_bar_mmap)
64        logging.debug(self.dev_info)
65
66        # Registers from HDA
67        self.hda_gctl = Register(self.hda_bar_mmap,
68                                 regs_def.HDA_GR_GCTL)
69        self.hda_gcap = Register(self.hda_bar_mmap,
70                                 regs_def.HDA_GR_GCAP, c_uint16)
71        self.hda_ppctl = Register(self.hda_bar_mmap,
72                                  regs_def.HDA_PPC_PPCTL)
73        self.hda_spibe = Register(self.hda_bar_mmap,
74                                  regs_def.HDA_SPBF_SPBFCTL)
75        # Registers from DSP
76        self.dsp_ctl_sts = Register(self.dsp_bar_mmap,
77                                    regs_def.ADSP_GR_ADSPCS)
78        self.dsp_hipci = Register(self.dsp_bar_mmap,
79                                  regs_def.ADSP_IPC_HIPCI)
80        self.dsp_hipcie = Register(self.dsp_bar_mmap,
81                                   regs_def.ADSP_IPC_HIPCIE)
82        self.dsp_hipct = Register(self.dsp_bar_mmap,
83                                  regs_def.ADSP_IPC_HIPCT)
84        self.fw_status = Register(self.dsp_bar_mmap,
85                                  plat_def.FW_STATUS)
86        self.fw_err_code = Register(self.dsp_bar_mmap,
87                                    plat_def.FW_ERR_CODE)
88        self.ipc_len = Register(self.dsp_bar_mmap,
89                                plat_def.FW_MBOX_UPLINK + plat_def.IPC_GLOBAL_LEN)
90        self.ipc_cmd = Register(self.dsp_bar_mmap,
91                                plat_def.FW_MBOX_UPLINK + plat_def.IPC_GLOBAL_CMD)
92
93        self.__opened = True
94        logging.debug("<<< Device.open_device()")
95
96    def alloc_memory(self, size):
97        logging.debug(">>> Device.alloc_memory()")
98        buf = self.drv.alloc_mem(size)
99        if buf.dma_addr_p == 0:
100            raise RuntimeError("Could not allocate the memory")
101        self.allocated.append(buf)
102        logging.debug("<<< Device.alloc_memory()")
103        return buf
104
105    def free_memory(self, mem):
106        logging.debug(">>> Device.free_memory()")
107        if mem in self.allocated:
108            ret = self.drv.free_mem(mem)
109            if ret != 0:
110                logging.error("Failed to free memory")
111            self.allocated.remove(mem)
112        else:
113            logging.warning("Cannot find the memory from list")
114        logging.debug("<<< Device.free_memory()")
115
116    def power_cycle(self):
117        logging.debug("Controller power down")
118        self.hda_gctl.value = 0
119        while self.hda_gctl.value != 0:
120            time.sleep(0.1)
121        logging.debug("   HDA_GCTL=%s" % self.hda_gctl)
122
123        logging.debug("Controller power up")
124        self.hda_gctl.value = 1
125        while self.hda_gctl.value != 1:
126            time.sleep(0.1)
127        logging.debug("   HDA_GCTL=%s" % self.hda_gctl)
128
129    def enable_proc_pipe_ctl(self):
130        logging.debug("Enable processing pipe control")
131        iss = ((self.hda_gcap.value & regs_def.HDA_GR_GCAP_ISS)
132                >> regs_def.HDA_GR_GCAP_ISS_OFFSET)
133        oss = ((self.hda_gcap.value & regs_def.HDA_GR_GCAP_OSS)
134                >> regs_def.HDA_GR_GCAP_OSS_OFFSET)
135
136        iss_mask = int("1" * iss, 2)
137        oss_mask = int("1" * oss, 2)
138
139        dma_mask = iss_mask + (oss_mask << iss)
140
141        # Enable processing pipe
142        self.hda_ppctl.value = self.hda_ppctl.value | 0x40000000 | dma_mask
143        logging.debug("   HDA_PPCTL=%s" % self.hda_ppctl)
144
145    def get_ipc_message(self):
146        logging.info("Read IPC message from DSP")
147        logging.info("IPC LEN: %s" % self.ipc_len)
148        logging.info("IPC CMD: %s" % self.ipc_cmd)
149
150    def core_reset_enter(self, core_mask):
151        # Set Reset Bit for cores
152        logging.debug("Enter core reset(mask=0x%08X)" % core_mask)
153
154        reset = core_mask << regs_def.ADSP_GR_ADSPCS_CRST_OFFSET
155        self._update_bits(self.dsp_ctl_sts, reset, reset)
156
157        # Check core entered reset
158        reg = self.dsp_ctl_sts.value
159        if (reg & reset) != reset:
160            raise RuntimeError("Reset enter failed: DSP_CTL_STS=%s core_maks=0x%08X"
161                               % (self.dsp_ctl_sts, core_mask))
162        logging.debug("   DSP_CTL_STS=%s" % self.dsp_ctl_sts)
163
164    def core_reset_leave(self, core_mask):
165        # Set Reset Bit for cores
166        logging.debug("Leave core reset(mask=0x%08X)" % core_mask)
167
168        leave = core_mask << regs_def.ADSP_GR_ADSPCS_CRST_OFFSET
169        self._update_bits(self.dsp_ctl_sts, leave, 0)
170
171        # Check core entered reset
172        reg = self.dsp_ctl_sts.value
173        if (reg & leave) != 0:
174            raise RuntimeError("Reset leave failed: DSP_CTL_STS=%s core_maks=0x%08X"
175                               % (self.dsp_ctl_sts, core_mask))
176        logging.debug("   DSP_CTL_STS=%s" % self.dsp_ctl_sts)
177
178    def core_stall_reset(self, core_mask):
179        logging.debug("Stall core(mask=0x%08X)" % core_mask)
180        stall = core_mask << regs_def.ADSP_GR_ADSPCS_CSTALL_OFFSET
181        self._update_bits(self.dsp_ctl_sts, stall, stall)
182        logging.debug("   DSP_CTL_STS=%s" % self.dsp_ctl_sts)
183        self.core_reset_enter(core_mask)
184
185    def core_run(self, core_mask):
186        self.core_reset_leave(core_mask)
187
188        logging.debug("Run/Unstall core(mask=0x%08X)" % core_mask)
189        run = core_mask << regs_def.ADSP_GR_ADSPCS_CSTALL_OFFSET
190        self._update_bits(self.dsp_ctl_sts, run, 0)
191        logging.debug("   DSP_CTL_STS=%s" % self.dsp_ctl_sts)
192
193    def core_power_down(self, core_mask):
194        logging.debug("Power down core(mask=0x%08X)" % core_mask)
195        mask = core_mask << regs_def.ADSP_GR_ADSPCS_SPA_OFFSET
196        self._update_bits(self.dsp_ctl_sts, mask, 0)
197
198        cnt = 0
199        while cnt < 10:
200            cpa = self.dsp_ctl_sts.value & regs_def.ADSP_GR_ADSPCS_CPA
201            mask = (core_mask & 0) << regs_def.ADSP_GR_ADSPCS_CPA_OFFSET
202            if cpa == mask:
203                logging.debug("Confirmed match value: 0x%04X" % cpa)
204                break
205            time.sleep(0.01)
206            cnt += 1
207
208        if cnt == 10:
209            logging.error("   DSP_CTL_STS=%s" % self.dsp_ctl_sts)
210            raise RuntimeError("Failed to power down the core")
211        logging.debug("   DSP_CTL_STS=%s" % self.dsp_ctl_sts)
212
213    def core_power_up(self, core_mask):
214        logging.debug("Power Up core(mask=0x%08X)" % core_mask)
215        mask = core_mask << regs_def.ADSP_GR_ADSPCS_SPA_OFFSET
216        self._update_bits(self.dsp_ctl_sts, mask, mask)
217
218        cnt = 0
219        while cnt < 10:
220            cpa = self.dsp_ctl_sts.value & regs_def.ADSP_GR_ADSPCS_CPA
221            mask = core_mask << regs_def.ADSP_GR_ADSPCS_CPA_OFFSET
222
223            if cpa == mask:
224                logging.debug("Confirmed match value: 0x%04X" % cpa)
225                break
226            time.sleep(0.01)
227            cnt += 1
228
229        if cnt == 10:
230            logging.error("   DSP_CTL_STS=%s" % self.dsp_ctl_sts)
231            raise RuntimeError("Failed to power up the core")
232
233        logging.debug("   DSP_CTL_STS=%s" % self.dsp_ctl_sts)
234
235    @staticmethod
236    def _update_bits(reg, mask, value):
237
238        old_val = reg.value
239        new_val = (old_val & ~mask) | (value & mask)
240
241        if old_val == new_val:
242            return False
243
244        reg.value = new_val
245        return True
246