1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4#
5# Copyright 2018, Data61
6# Commonwealth Scientific and Industrial Research Organisation (CSIRO)
7# ABN 41 687 119 230.
8#
9# This software may be distributed and modified according to the terms of
10# the BSD 2-Clause license. Note that NO WARRANTY is provided.
11# See "LICENSE_BSD2.txt" for details.
12#
13# @TAG(DATA61_BSD)
14#
15
16from __future__ import absolute_import, division, print_function, unicode_literals
17
18from camkes.parser import ParseError, DtbMatchQuery
19from camkes.internal.tests.utils import CAmkESTest
20import os
21import sys
22import unittest
23
24ME = os.path.abspath(__file__)
25
26# Make CAmkES importable
27sys.path.append(os.path.join(os.path.dirname(ME), '../../..'))
28
29
30class TestDTBMatchQuery(CAmkESTest):
31    '''
32    As part of the changes brought by the new seL4DTBHardware connector,
33    the DTB dictionary now includes keys 'this-address-cells' and 'this-size-cells'.
34    The keys describe the number of cells required to express those particular fields in
35    the 'reg' property of the DTB.
36
37    As part of the changes brought by exposing the DTB to CAmkES userland, the DTB dictionary
38    now includes a 'dtb_size' key. This key-value pair describes the size of the DTB, in bytes.
39    '''
40
41    def setUp(self):
42        super(TestDTBMatchQuery, self).setUp()
43        self.dtbQuery = DtbMatchQuery()
44        self.dtbQuery.parse_args(['--dtb', os.path.join(os.path.dirname(ME), "test.dtb")])
45        self.dtbQuery.check_options()
46        self.dtbSize = os.path.getsize(os.path.join(os.path.dirname(ME), "test.dtb"))
47
48    def test_aliases(self):
49        node = self.dtbQuery.resolve([{'aliases': 'usbphy0'}])
50        self.assertIsInstance(node, dict)
51
52        expected = {
53            'compatible': ["fsl,imx6q-usbphy", "fsl,imx23-usbphy"],
54            'reg': [0x20c9000, 0x1000],
55            'interrupts': [0x0, 0x2c, 0x4],
56            'clocks': [0x4, 0xb6],
57            'fsl,anatop': [0x2],
58            'phandle': [0x2c],
59            'this-address-cells': [0x1],
60            'this-size-cells': [0x1],
61            'this-node-path': "/soc/aips-bus@2000000/usbphy@20c9000",
62        }
63        self.assertIn('query', node)
64        self.assertIn('dtb-size', node)
65        self.assertEquals(len(node['query']), 1)
66        self.assertEquals(node['query'][0], expected)
67        self.assertEquals(node['dtb-size'], [self.dtbSize])
68
69        node = self.dtbQuery.resolve([{'aliases': 'spi4'}])
70        expected = {
71            '#address-cells': [0x1],
72            '#size-cells': [0x0],
73            'compatible': ["fsl,imx6q-ecspi", "fsl,imx51-ecspi"],
74            'reg': [0x2018000, 0x4000],
75            'interrupts': [0x0, 0x23, 0x4],
76            'clocks': [0x4, 0x74, 0x4, 0x74],
77            'clock-names': ["ipg", "per"],
78            'dmas': [0x17, 0xb, 0x8, 0x1, 0x17, 0xc, 0x8, 0x2],
79            'dma-names': ["rx", "tx"],
80            'status': ["disabled"],
81            'this-address-cells': [0x1],
82            'this-size-cells': [0x1],
83            'this-node-path': "/soc/aips-bus@2000000/spba-bus@2000000/ecspi@2018000",
84        }
85
86        self.assertIn('query', node)
87        self.assertEquals(node['query'][0], expected)
88        self.assertEquals(len(node['query']), 1)
89        self.assertEquals(node['dtb-size'], [self.dtbSize])
90
91    def test_paths(self):
92        node = self.dtbQuery.resolve([{'path': "temp"}])
93        expected = {
94            'compatible': ["fsl,imx6q-tempmon"],
95            'interrupt-parent': [0x1],
96            'interrupts': [0x0, 0x31, 0x4],
97            'fsl,tempmon': [0x2],
98            'fsl,tempmon-data': [0x3],
99            'clocks': [0x4, 0xac],
100            'this-address-cells': [0x1],
101            'this-size-cells': [0x1],
102            'this-node-path': "/tempmon",
103        }
104        self.assertIn('query', node)
105        self.assertEquals(len(node['query']), 1)
106        self.assertEquals(node['query'][0], expected)
107
108        node = self.dtbQuery.resolve([{'path': '.*serial.*'}])
109        expected = {
110            'compatible': ["fsl,imx6q-uart", "fsl,imx21-uart"],
111            'reg': [0x2020000, 0x4000],
112            'interrupts': [0x0, 0x1a, 0x4],
113            'clocks': [0x4, 0xa0, 0x4, 0xa1],
114            'clock-names': ["ipg", "per"],
115            'dmas': [0x17, 0x19, 0x4, 0x0, 0x17, 0x1a, 0x4, 0x0],
116            'dma-names': ["rx", "tx"],
117            'status': ["okay"],
118            'pinctrl-names': ["default"],
119            'pinctrl-0': [0x1a],
120            'this-address-cells': [0x1],
121            'this-size-cells': [0x1],
122            'this-node-path': "/soc/aips-bus@2000000/spba-bus@2000000/serial@2020000",
123        }
124        self.assertIn('query', node)
125        self.assertEquals(len(node['query']), 1)
126        self.assertEquals(node['query'][0], expected)
127        self.assertEquals(node['dtb-size'], [self.dtbSize])
128
129        node = self.dtbQuery.resolve([{'path': '.*sgtl5000.*'}])
130        expected = {
131            'compatible': ["fsl,sgtl5000"],
132            'reg': [0x0a],
133            'clocks': [0x04, 0xc9],
134            'VDDA-supply': [0x39],
135            'VDDIO-supply': [0x35],
136            'phandle': [0x78],
137            'this-address-cells': [0x01],
138            'this-size-cells': [0x00],
139            'this-node-path': "/soc/aips-bus@2100000/i2c@21a0000/sgtl5000@a",
140        }
141        self.assertIn('query', node)
142        self.assertEquals(len(node['query']), 1)
143        self.assertEquals(node['query'][0], expected)
144        self.assertEquals(node['dtb-size'], [self.dtbSize])
145
146    def test_multiple_queries(self):
147        node = self.dtbQuery.resolve([{'path': "temp"}, {'aliases': 'spi4'}])
148        expected = [
149            {
150                'compatible': ["fsl,imx6q-tempmon"],
151                'interrupt-parent': [0x1],
152                'interrupts': [0x0, 0x31, 0x4],
153                'fsl,tempmon': [0x2],
154                'fsl,tempmon-data': [0x3],
155                'clocks': [0x4, 0xac],
156                'this-address-cells': [0x1],
157                'this-size-cells': [0x1],
158                'this-node-path': "/tempmon",
159            },
160            {
161                '#address-cells': [0x1],
162                '#size-cells': [0x0],
163                'compatible': ["fsl,imx6q-ecspi", "fsl,imx51-ecspi"],
164                'reg': [0x2018000, 0x4000],
165                'interrupts': [0x0, 0x23, 0x4],
166                'clocks': [0x4, 0x74, 0x4, 0x74],
167                'clock-names': ["ipg", "per"],
168                'dmas': [0x17, 0xb, 0x8, 0x1, 0x17, 0xc, 0x8, 0x2],
169                'dma-names': ["rx", "tx"],
170                'status': ["disabled"],
171                'this-address-cells': [0x1],
172                'this-size-cells': [0x1],
173                'this-node-path': "/soc/aips-bus@2000000/spba-bus@2000000/ecspi@2018000",
174            }
175        ]
176        self.assertIn('query', node)
177        self.assertEquals(len(node['query']), 2)
178        self.assertEquals(node['query'][0], expected[0])
179        self.assertEquals(node['query'][1], expected[1])
180
181        node = self.dtbQuery.resolve(
182            [{'path': '.*sgtl5000.*'}, {'properties': {'reg[0]': 0x2020000}}])
183        expected = [
184            {
185                'compatible': ["fsl,sgtl5000"],
186                'reg': [0x0a],
187                'clocks': [0x04, 0xc9],
188                'VDDA-supply': [0x39],
189                'VDDIO-supply': [0x35],
190                'phandle': [0x78],
191                'this-address-cells': [0x01],
192                'this-size-cells': [0x00],
193                'this-node-path': "/soc/aips-bus@2100000/i2c@21a0000/sgtl5000@a",
194            },
195            {
196                'dma-names': ['rx', 'tx'],
197                'status': ['okay'],
198                'clock-names': ['ipg', 'per'],
199                'interrupts': [0, 26, 4],
200                'pinctrl-names': ['default'],
201                'compatible': ['fsl,imx6q-uart', 'fsl,imx21-uart'],
202                'dmas': [23, 25, 4, 0, 23, 26, 4, 0],
203                'clocks': [4, 160, 4, 161],
204                'pinctrl-0': [26],
205                'reg': [33685504, 16384],
206                'this-address-cells': [0x1],
207                'this-size-cells': [0x1],
208                'this-node-path': "/soc/aips-bus@2000000/spba-bus@2000000/serial@2020000",
209            }
210        ]
211        self.assertIn('query', node)
212        self.assertEquals(len(node['query']), 2)
213        self.assertEquals(node['query'][0], expected[0])
214        self.assertEquals(node['query'][1], expected[1])
215        self.assertEquals(node['dtb-size'], [self.dtbSize])
216
217    def test_blank(self):
218        self.assertRaises(ParseError, self.dtbQuery.resolve, [])
219
220    def test_blank_query(self):
221        node = self.dtbQuery.resolve([{}])
222        self.assertIn('query', node)
223        self.assertEquals(len(node['query']), 1)
224        self.assertEquals(node['query'][0], {})
225
226    def test_properties_lvalue_index(self):
227        node = self.dtbQuery.resolve([{'properties': {'reg[0]': 0x2020000}}])
228        expected = {
229            'dma-names': ['rx', 'tx'],
230            'status': ['okay'],
231            'clock-names': ['ipg', 'per'],
232            'interrupts': [0, 26, 4],
233            'pinctrl-names': ['default'],
234            'compatible': ['fsl,imx6q-uart', 'fsl,imx21-uart'],
235            'dmas': [23, 25, 4, 0, 23, 26, 4, 0],
236            'clocks': [4, 160, 4, 161],
237            'pinctrl-0': [26],
238            'reg': [33685504, 16384],
239            'this-address-cells': [0x1],
240            'this-size-cells': [0x1],
241            'this-node-path': "/soc/aips-bus@2000000/spba-bus@2000000/serial@2020000",
242        }
243        self.assertIn('query', node)
244        self.assertEquals(len(node['query']), 1)
245        self.assertEquals(node['query'][0], expected)
246        self.assertEquals(node['dtb-size'], [self.dtbSize])
247
248        node = self.dtbQuery.resolve([{'properties': {'compatible[0]': 'fsl,imx6q-pwm'}}])
249        expected = {
250            'status': ['okay'],
251            'pinctrl-0': [29],
252            'clock-names': ['ipg', 'per'],
253            'interrupts': [0, 83, 4],
254            '#pwm-cells': [2],
255            'pinctrl-names': ['default'],
256            'compatible': ['fsl,imx6q-pwm', 'fsl,imx27-pwm'],
257            'clocks': [4, 62, 4, 145],
258            'phandle': [121],
259            'reg': [34078720, 16384],
260            'this-address-cells': [0x1],
261            'this-size-cells': [0x1],
262            'this-node-path': "/soc/aips-bus@2000000/pwm@2080000",
263        }
264        self.assertIn('query', node)
265        self.assertEquals(len(node['query']), 1)
266        self.assertEquals(node['query'][0], expected)
267        self.assertEquals(node['dtb-size'], [self.dtbSize])
268
269        node = self.dtbQuery.resolve([{'properties': {'compatible[0]': 'fsl,sec-v4.0-mon-rtc-lp'}}])
270        expected = {
271            'compatible': ['fsl,sec-v4.0-mon-rtc-lp'],
272            'regmap': [0x23],
273            'offset': [0x34],
274            'interrupts': [0x00, 0x13, 0x04, 0x00, 0x14, 0x04],
275            'this-address-cells': [0x02],
276            'this-size-cells': [0x01],
277            'this-node-path': "/soc/aips-bus@2000000/snvs@20cc000/snvs-rtc-lp",
278        }
279        self.assertIn('query', node)
280        self.assertEquals(len(node['query']), 1)
281        self.assertEquals(node['query'][0], expected)
282        self.assertEquals(node['dtb-size'], [self.dtbSize])
283
284    def test_properties_star_string(self):
285        node = self.dtbQuery.resolve([{
286            'properties':  {
287                "clock-names[*]": ["di0_pll", "di1_pll", "di0_sel", "di1_sel", "di2_sel", "di3_sel", "di0", "di1"]
288            }
289        }])
290        self.assertIn('query', node)
291        self.assertEquals(len(node['query']), 1)
292        query = node['query'][0]
293
294        self.assertIn('#address-cells', query)
295        self.assertEquals(query['#address-cells'], [0x1])
296
297        self.assertIn('#size-cells', query)
298        self.assertEquals(query['#size-cells'], [0x0])
299
300        self.assertIn('compatible', query)
301        self.assertEquals(query['compatible'], ["fsl,imx6q-ldb", "fsl,imx53-ldb"])
302
303        self.assertIn('gpr', query)
304        self.assertEquals(query['gpr'], [0x5])
305
306        self.assertIn('status', query)
307        self.assertEquals(query['status'], ["okay"])
308
309        self.assertIn('clocks', query)
310        self.assertEquals(query['clocks'], [0x4, 0x21, 0x4, 0x22, 0x4, 0x27, 0x4, 0x28, 0x4, 0x29, 0x4, 0x2a, 0x4, 0x87,
311                                            0x4, 0x88])
312
313        self.assertIn('clock-names', query)
314        self.assertEquals(query['clock-names'], ["di0_pll", "di1_pll", "di0_sel", "di1_sel", "di2_sel", "di3_sel",
315                                                 "di0", "di1"])
316
317        self.assertIn('this-address-cells', query)
318        self.assertEquals(query['this-address-cells'], [0x1])
319
320        self.assertIn('this-size-cells', query)
321        self.assertEquals(query['this-size-cells'], [0x1])
322
323        self.assertIn('dtb-size', node)
324        self.assertEquals(node['dtb-size'], [self.dtbSize])
325
326        node = self.dtbQuery.resolve([{
327            'properties': {
328                "interrupt-names[*]": ["gpmi0", "gpmi1", "gpmi2", "gpmi3"]
329            }
330        }])
331        self.assertIn('query', node)
332        self.assertEquals(len(node['query']), 1)
333        query = node['query'][0]
334
335        expected = {
336            'compatible': ["fsl,imx6q-dma-apbh", "fsl,imx28-dma-apbh"],
337            'reg': [0x110000, 0x2000],
338            'interrupts': [0x0, 0xd, 0x4, 0x0, 0xd, 0x4, 0x0, 0xd, 0x4, 0x0, 0xd, 0x4],
339            'interrupt-names': ["gpmi0", "gpmi1", "gpmi2", "gpmi3"],
340            '#dma-cells': [0x1],
341            'dma-channels': [0x4],
342            'clocks': [0x4, 0x6a],
343            'phandle': [0xf],
344            'this-address-cells': [0x1],
345            'this-size-cells': [0x1],
346            'this-node-path': "/soc/dma-apbh@110000",
347        }
348        self.assertEquals(query, expected)
349        self.assertIn('dtb-size', node)
350        self.assertEquals(node['dtb-size'], [self.dtbSize])
351
352        node = self.dtbQuery.resolve([{
353            'properties': {
354                "compatible[*]": ["fsl,imx6q-pcie", "snps,dw-pcie"]
355            }
356        }])
357
358        self.assertIn('query', node)
359        self.assertEquals(len(node['query']), 1)
360        query = node['query'][0]
361        expected = {
362            'compatible': ["fsl,imx6q-pcie", "snps,dw-pcie"],
363            'reg': [0x1ffc000, 0x4000, 0x1f00000, 0x80000],
364            'reg-names': ["dbi", "config"],
365            '#address-cells': [0x3],
366            '#size-cells': [0x2],
367            'device_type': ["pci"],
368            'bus-range': [0x0, 0xff],
369            'ranges': [0x81000000, 0x0, 0x0, 0x1f80000, 0x0, 0x10000, 0x82000000, 0x0, 0x1000000, 0x1000000, 0x0,
370                       0xf00000],
371            'num-lanes': [0x1],
372            'interrupts': [0x0, 0x78, 0x4],
373            'interrupt-names': ["msi"],
374            '#interrupt-cells': [0x1],
375            'interrupt-map-mask': [0x0, 0x0, 0x0, 0x7],
376            'interrupt-map': [0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x7b, 0x4, 0x0, 0x0, 0x0, 0x2, 0x1, 0x0, 0x7a, 0x4, 0x0,
377                              0x0, 0x0, 0x3, 0x1, 0x0, 0x79, 0x4, 0x0, 0x0, 0x0, 0x4, 0x1, 0x0, 0x78, 0x4],
378            'clocks': [0x4, 0x90, 0x4, 0xce, 0x4, 0xbd],
379            'clock-names': ["pcie", "pcie_bus", "pcie_phy"],
380            'status': ["okay"],
381            'this-address-cells': [0x1],
382            'this-size-cells': [0x1],
383            'this-node-path': "/soc/pcie@1ffc000",
384        }
385        self.assertEquals(query, expected)
386        self.assertIn('dtb-size', node)
387        self.assertEquals(node['dtb-size'], [self.dtbSize])
388
389    def test_properties_star_word_and_byte(self):
390        node = self.dtbQuery.resolve([{
391            'properties': {
392                "clocks[*]": [0x4, 0x98, 0x4, 0x99, 0x4, 0x97, 0x4, 0x96, 0x4, 0x95]
393            }
394        }])
395
396        self.assertIn('query', node)
397        self.assertEquals(len(node['query']), 1)
398        query = node['query'][0]
399        expected = {
400            'compatible': ["fsl,imx6q-gpmi-nand"],
401            '#address-cells': [0x1],
402            '#size-cells': [0x1],
403            'reg': [0x112000, 0x2000, 0x114000, 0x2000],
404            'reg-names': ["gpmi-nand", "bch"],
405            'interrupts': [0x0, 0xf, 0x4],
406            'interrupt-names': ["bch"],
407            'clocks': [0x4, 0x98, 0x4, 0x99, 0x4, 0x97, 0x4, 0x96, 0x4, 0x95],
408            'clock-names': ["gpmi_io", "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch"],
409            'dmas': [0xf, 0x0],
410            'dma-names': ["rx-tx"],
411            'status': ["disabled"],
412            'this-address-cells': [0x1],
413            'this-size-cells': [0x1],
414            'this-node-path': "/soc/gpmi-nand@112000",
415        }
416        self.assertEquals(query, expected)
417        self.assertIn('dtb-size', node)
418        self.assertEquals(node['dtb-size'], [self.dtbSize])
419
420
421if __name__ == '__main__':
422    unittest.main()
423