blob: 93bc595bc8dd2fd424dd01091ef56a1e151b34fe [file] [log] [blame]
David Burger7fd1dbe2020-03-26 09:26:55 -06001#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# Copyright 2020 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6"""Transforms config from /config/proto/api proto format to platform JSON."""
7
Ren-Pei Zengce869dd2020-08-18 01:29:37 +08008# pylint: disable=too-many-lines
9
David Burger7fd1dbe2020-03-26 09:26:55 -060010import argparse
11import json
12import pprint
C Shapiro90fda252020-04-17 14:34:57 -050013import os
David Burger7fd1dbe2020-03-26 09:26:55 -060014import sys
C Shapiro90fda252020-04-17 14:34:57 -050015import re
C Shapiro5bf23a72020-04-24 11:40:17 -050016import xml.etree.ElementTree as etree
C Shapiro9a3ac8c2020-04-25 07:49:21 -050017import xml.dom.minidom as minidom
David Burger7fd1dbe2020-03-26 09:26:55 -060018
Andrew Lamb319cc922020-06-15 10:45:46 -060019from typing import List
20
David Burger7fd1dbe2020-03-26 09:26:55 -060021from collections import namedtuple
22
Andrew Lambcd33f702020-06-11 10:45:16 -060023from google.protobuf import json_format
24
Prathmesh Prabhu72f8a002020-04-10 09:57:53 -070025from chromiumos.config.api import device_brand_pb2
David Burger92609a32020-04-23 10:38:50 -060026from chromiumos.config.api import topology_pb2
C Shapiro5bf23a72020-04-24 11:40:17 -050027from chromiumos.config.payload import config_bundle_pb2
Prathmesh Prabhu72f8a002020-04-10 09:57:53 -070028from chromiumos.config.api.software import brand_config_pb2
David Burger7fd1dbe2020-03-26 09:26:55 -060029
Andrew Lamb2413c982020-05-29 12:15:36 -060030Config = namedtuple('Config', [
31 'program', 'hw_design', 'odm', 'hw_design_config', 'device_brand',
32 'device_signer_config', 'oem', 'sw_config', 'brand_config', 'build_target'
33])
David Burger7fd1dbe2020-03-26 09:26:55 -060034
David Burger07af5242020-08-11 11:08:25 -060035ConfigFiles = namedtuple(
David Burgerceeb68a2020-09-03 11:31:10 -060036 'ConfigFiles',
37 ['arc_hw_features', 'touch_fw', 'dptf_map', 'camera_map', 'wifi_sar_map'])
David Burger8ee9b4d2020-06-16 17:40:21 -060038
39CAMERA_CONFIG_DEST_PATH_TEMPLATE = '/etc/camera/camera_config_{}.json'
40CAMERA_CONFIG_SOURCE_PATH_TEMPLATE = (
41 'sw_build_config/platform/chromeos-config/camera/camera_config_{}.json')
C Shapiro5bf23a72020-04-24 11:40:17 -050042
David Burger52c9d322020-06-09 07:16:18 -060043DPTF_PATH = 'sw_build_config/platform/chromeos-config/thermal'
44DPTF_FILE = 'dptf.dv'
David Burger2f0d9522020-07-30 10:52:28 -060045
C Shapiro2b6d5332020-05-06 17:51:35 -050046TOUCH_PATH = 'sw_build_config/platform/chromeos-config/touch'
Andrew Lamb6c42efc2020-06-16 10:40:43 -060047WALLPAPER_BASE_PATH = '/usr/share/chromeos-assets/wallpaper'
David Burger7fd1dbe2020-03-26 09:26:55 -060048
Andrew Lamb2413c982020-05-29 12:15:36 -060049
Andrew Lambcd33f702020-06-11 10:45:16 -060050def parse_args(argv):
David Burger7fd1dbe2020-03-26 09:26:55 -060051 """Parse the available arguments.
52
53 Invalid arguments or -h cause this function to print a message and exit.
54
55 Args:
56 argv: List of string arguments (excluding program name / argv[0])
57
58 Returns:
59 argparse.Namespace object containing the attributes.
60 """
61 parser = argparse.ArgumentParser(
62 description='Converts source proto config into platform JSON config.')
63 parser.add_argument(
64 '-c',
65 '--project_configs',
66 nargs='+',
67 type=str,
68 help='Space delimited list of source protobinary project config files.')
69 parser.add_argument(
70 '-p',
71 '--program_config',
72 type=str,
73 help='Path to the source program-level protobinary file')
74 parser.add_argument(
Andrew Lamb2413c982020-05-29 12:15:36 -060075 '-o', '--output', type=str, help='Output file that will be generated')
David Burger7fd1dbe2020-03-26 09:26:55 -060076 return parser.parse_args(argv)
77
78
David Burger8ee9b4d2020-06-16 17:40:21 -060079def _upsert(field, target, target_name):
80 """Updates or inserts `field` within `target`.
81
82 If `target_name` already exists within `target` an update is performed,
83 otherwise, an insert is performed.
84 """
Sam McNally9a873f72020-06-05 19:47:22 +100085 if field or field == 0:
David Burger8ee9b4d2020-06-16 17:40:21 -060086 if target_name in target:
87 target[target_name].update(field)
88 else:
89 target[target_name] = field
David Burger7fd1dbe2020-03-26 09:26:55 -060090
91
Andrew Lambcd33f702020-06-11 10:45:16 -060092def _build_arc(config, config_files):
93 if not config.build_target.arc:
94 return None
95
96 build_properties = {
97 'device': config.build_target.arc.device,
98 'first-api-level': config.build_target.arc.first_api_level,
99 'marketing-name': config.device_brand.brand_name,
100 'metrics-tag': config.hw_design.name.lower(),
101 'product': config.build_target.id.value,
102 }
103 if config.oem:
104 build_properties['oem'] = config.oem.name
105 result = {'build-properties': build_properties}
106 feature_id = _arc_hardware_feature_id(config.hw_design_config)
107 if feature_id in config_files.arc_hw_features:
108 result['hardware-features'] = config_files.arc_hw_features[feature_id]
109 topology = config.hw_design_config.hardware_topology
110 ppi = topology.screen.hardware_feature.screen.panel_properties.pixels_per_in
111 # Only set for high resolution displays
112 if ppi and ppi > 250:
113 result['scale'] = ppi
David Burger2f0d9522020-07-30 10:52:28 -0600114
Andrew Lambcd33f702020-06-11 10:45:16 -0600115 return result
David Burger7fd1dbe2020-03-26 09:26:55 -0600116
Andrew Lamb2413c982020-05-29 12:15:36 -0600117
Andrew Lamb319cc922020-06-15 10:45:46 -0600118def _build_ash_flags(config: Config) -> List[str]:
119 """Returns a list of Ash flags for config.
120
121 Ash is the window manager and system UI for ChromeOS, see
122 https://chromium.googlesource.com/chromium/src/+/refs/heads/master/ash/.
123 """
124 # A map from flag name -> value. Value may be None for boolean flags.
125 flags = {}
126
127 hw_features = config.hw_design_config.hardware_features
128 if hw_features.stylus.stylus == topology_pb2.HardwareFeatures.Stylus.INTERNAL:
Andrew Lamb2e641e22020-06-15 12:30:41 -0600129 flags['has-internal-stylus'] = None
Andrew Lamb319cc922020-06-15 10:45:46 -0600130
Andrew Lamb2e641e22020-06-15 12:30:41 -0600131 fp_loc = hw_features.fingerprint.location
132 if fp_loc and fp_loc != topology_pb2.HardwareFeatures.Fingerprint.NOT_PRESENT:
133 loc_name = topology_pb2.HardwareFeatures.Fingerprint.Location.Name(fp_loc)
134 flags['fingerprint-sensor-location'] = loc_name.lower().replace('_', '-')
135
Andrew Lamb6c42efc2020-06-16 10:40:43 -0600136 wallpaper = config.brand_config.wallpaper
137 # If a wallpaper is set, the 'default-wallpaper-is-oem' flag needs to be set.
138 # If a wallpaper is not set, the 'default_[large|small].jpg' wallpapers
139 # should still be set.
140 if wallpaper:
141 flags['default-wallpaper-is-oem'] = None
142 else:
143 wallpaper = 'default'
144
145 for size in ('small', 'large'):
146 flags[f'default-wallpaper-{size}'] = (
147 f'{WALLPAPER_BASE_PATH}/{wallpaper}_{size}.jpg')
148
149 # For each size, also install 'guest' and 'child' wallpapers.
150 for wallpaper_type in ('guest', 'child'):
151 flags[f'{wallpaper_type}-wallpaper-{size}'] = (
152 f'{WALLPAPER_BASE_PATH}/{wallpaper_type}_{size}.jpg')
153
C Shapiro2e97aad2020-11-16 11:58:10 -0600154 regulatory_label = config.brand_config.regulatory_label
155 if regulatory_label:
156 flags['regulatory-label-dir'] = (regulatory_label)
157
Andrew Lamb72d41362020-06-17 09:19:02 -0600158 flags['arc-build-properties'] = json_format.MessageToDict(
159 config.build_target.arc)
160
Andrew Lamb90b168c2020-06-22 10:42:30 -0600161 power_button = hw_features.power_button
162 if power_button.edge:
163 flags['ash-power-button-position'] = json.dumps({
164 'edge':
165 topology_pb2.HardwareFeatures.Button.Edge.Name(power_button.edge
166 ).lower(),
167 # Starlark sometimes represents float literals strangely, e.g. changing
168 # 0.9 to 0.899999. Round to two digits here.
169 'position':
170 round(power_button.position, 2)
171 })
172
173 volume_button = hw_features.volume_button
174 if volume_button.edge:
175 flags['ash-side-volume-button-position'] = json.dumps({
176 'region':
177 topology_pb2.HardwareFeatures.Button.Region.Name(
178 volume_button.region).lower(),
179 'edge':
180 topology_pb2.HardwareFeatures.Button.Edge.Name(volume_button.edge
181 ).lower(),
182 })
183
Andrew Lamb2e641e22020-06-15 12:30:41 -0600184 return sorted([f'--{k}={v}' if v else f'--{k}' for k, v in flags.items()])
Andrew Lamb319cc922020-06-15 10:45:46 -0600185
186
187def _build_ui(config: Config) -> dict:
188 """Builds the 'ui' property from cros_config_schema."""
189 return {'extra-ash-flags': _build_ash_flags(config)}
190
191
David Burger07af5242020-08-11 11:08:25 -0600192def _build_bluetooth(config):
C Shapiro90fda252020-04-17 14:34:57 -0500193 bt_flags = config.sw_config.bluetooth_config.flags
194 # Convert to native map (from proto wrapper)
195 bt_flags_map = dict(bt_flags)
196 result = {}
197 if bt_flags_map:
198 result['flags'] = bt_flags_map
C Shapiro90fda252020-04-17 14:34:57 -0500199 return result
200
David Burger7fd1dbe2020-03-26 09:26:55 -0600201
David Burgerceeb68a2020-09-03 11:31:10 -0600202def _build_ath10k_config(ath10k_config):
203 """Builds the wifi configuration for the ath10k driver.
204
205 Args:
206 ath10k_config: Ath10kConfig config.
207
208 Returns:
209 wifi configuration for the ath10k driver.
210 """
David Burgerec753912020-08-10 12:59:11 -0600211 result = {}
David Burgerec753912020-08-10 12:59:11 -0600212
David Burgerceeb68a2020-09-03 11:31:10 -0600213 def power_chain(power):
214 return {
215 'limit-2g': power.limit_2g,
216 'limit-5g': power.limit_5g,
217 }
David Burgerec753912020-08-10 12:59:11 -0600218
David Burgerceeb68a2020-09-03 11:31:10 -0600219 result['tablet-mode-power-table-ath10k'] = power_chain(
220 ath10k_config.tablet_mode_power_table)
221 result['non-tablet-mode-power-table-ath10k'] = power_chain(
222 ath10k_config.non_tablet_mode_power_table)
David Burgerec753912020-08-10 12:59:11 -0600223 return result
224
225
David Burgerceeb68a2020-09-03 11:31:10 -0600226def _build_rtw88_config(rtw88_config):
227 """Builds the wifi configuration for the rtw88 driver.
228
229 Args:
230 rtw88_config: Rtw88Config config.
231
232 Returns:
233 wifi configuration for the rtw88 driver.
234 """
235 result = {}
236
237 def power_chain(power):
238 return {
239 'limit-2g': power.limit_2g,
240 'limit-5g-1': power.limit_5g_1,
241 'limit-5g-3': power.limit_5g_3,
242 'limit-5g-4': power.limit_5g_4,
243 }
244
245 result['tablet-mode-power-table-rtw'] = power_chain(
246 rtw88_config.tablet_mode_power_table)
247 result['non-tablet-mode-power-table-rtw'] = power_chain(
248 rtw88_config.non_tablet_mode_power_table)
249
250 def offsets(offset):
251 return {
252 'offset-2g': offset.offset_2g,
253 'offset-5g': offset.offset_5g,
254 }
255
256 result['geo-offsets-fcc'] = offsets(rtw88_config.offset_fcc)
257 result['geo-offsets-eu'] = offsets(rtw88_config.offset_eu)
258 result['geo-offsets-rest-of-world'] = offsets(rtw88_config.offset_other)
259 return result
260
261
262def _build_intel_config(config, config_files):
263 """Builds the wifi configuration for the intel driver.
264
265 Args:
266 config: Config namedtuple
267 config_files: Map to look up the generated config files.
268
269 Returns:
270 wifi configuration for the intel driver.
271 """
272 design_name = config.hw_design.name.lower()
273 return config_files.wifi_sar_map.get(design_name)
274
275
276def _build_wifi(config, config_files):
277 """Builds the wifi configuration.
278
279 Args:
280 config: Config namedtuple
281 config_files: Map to look up the generated config files.
282
283 Returns:
284 wifi configuration.
285 """
286 config_field = config.sw_config.wifi_config.WhichOneof('wifi_config')
287 if config_field == 'ath10k_config':
288 return _build_ath10k_config(config.sw_config.wifi_config.ath10k_config)
289 if config_field == 'rtw88_config':
290 return _build_rtw88_config(config.sw_config.wifi_config.rtw88_config)
291 if config_field == 'intel_config':
292 return _build_intel_config(config, config_files)
293 return {}
294
295
Andrew Lambcd33f702020-06-11 10:45:16 -0600296def _build_fingerprint(hw_topology):
297 if not hw_topology.HasField('fingerprint'):
298 return None
299
300 fp = hw_topology.fingerprint.hardware_feature.fingerprint
301 result = {}
302 if fp.location != topology_pb2.HardwareFeatures.Fingerprint.NOT_PRESENT:
303 location = fp.Location.DESCRIPTOR.values_by_number[fp.location].name
304 result['sensor-location'] = location.lower().replace('_', '-')
305 if fp.board:
306 result['board'] = fp.board
Tom Hughesdfc35402020-06-29 16:02:09 -0700307 if fp.ro_version:
308 result['ro-version'] = fp.ro_version
309
Andrew Lambcd33f702020-06-11 10:45:16 -0600310 return result
David Burger7fd1dbe2020-03-26 09:26:55 -0600311
312
Trent Beginf067ccb2020-08-12 12:33:53 -0600313def _build_hardware_properties(hw_topology):
314 if not hw_topology.HasField('form_factor'):
315 return None
316
317 form_factor = hw_topology.form_factor.hardware_feature.form_factor.form_factor
318 result = {}
319 if form_factor in [
320 topology_pb2.HardwareFeatures.FormFactor.CHROMEBIT,
321 topology_pb2.HardwareFeatures.FormFactor.CHROMEBASE,
322 topology_pb2.HardwareFeatures.FormFactor.CHROMEBOX
323 ]:
324 result['psu-type'] = "AC_only"
325 else:
326 result['psu-type'] = "battery"
327
328 result['has-backlight'] = form_factor not in [
329 topology_pb2.HardwareFeatures.FormFactor.CHROMEBIT,
330 topology_pb2.HardwareFeatures.FormFactor.CHROMEBOX
331 ]
332
333 return result
334
335
Andrew Lambcd33f702020-06-11 10:45:16 -0600336def _fw_bcs_path(payload):
David Burger7fd1dbe2020-03-26 09:26:55 -0600337 if payload and payload.firmware_image_name:
Andrew Lamb2413c982020-05-29 12:15:36 -0600338 return 'bcs://%s.%d.%d.0.tbz2' % (payload.firmware_image_name,
339 payload.version.major,
340 payload.version.minor)
David Burger7fd1dbe2020-03-26 09:26:55 -0600341
Andrew Lambcd33f702020-06-11 10:45:16 -0600342 return None
David Burger7fd1dbe2020-03-26 09:26:55 -0600343
Andrew Lambcd33f702020-06-11 10:45:16 -0600344
345def _fw_build_target(payload):
David Burger7fd1dbe2020-03-26 09:26:55 -0600346 if payload:
347 return payload.build_target_name
348
Andrew Lambcd33f702020-06-11 10:45:16 -0600349 return None
David Burger7fd1dbe2020-03-26 09:26:55 -0600350
Andrew Lambcd33f702020-06-11 10:45:16 -0600351
352def _build_firmware(config):
David Burgerb70b6762020-05-21 12:14:59 -0600353 """Returns firmware config, or None if no build targets."""
Andrew Lamb3da156d2020-04-16 16:00:56 -0600354 fw_payload_config = config.sw_config.firmware
355 fw_build_config = config.sw_config.firmware_build_config
356 main_ro = fw_payload_config.main_ro_payload
357 main_rw = fw_payload_config.main_rw_payload
358 ec_ro = fw_payload_config.ec_ro_payload
359 pd_ro = fw_payload_config.pd_ro_payload
David Burger7fd1dbe2020-03-26 09:26:55 -0600360
361 build_targets = {}
Andrew Lamb3da156d2020-04-16 16:00:56 -0600362
David Burger8ee9b4d2020-06-16 17:40:21 -0600363 _upsert(fw_build_config.build_targets.depthcharge, build_targets,
364 'depthcharge')
365 _upsert(fw_build_config.build_targets.coreboot, build_targets, 'coreboot')
366 _upsert(fw_build_config.build_targets.ec, build_targets, 'ec')
367 _upsert(
Andrew Lambf8954ee2020-04-21 10:24:40 -0600368 list(fw_build_config.build_targets.ec_extras), build_targets, 'ec_extras')
David Burger8ee9b4d2020-06-16 17:40:21 -0600369 _upsert(fw_build_config.build_targets.libpayload, build_targets, 'libpayload')
David Burger7fd1dbe2020-03-26 09:26:55 -0600370
David Burgerb70b6762020-05-21 12:14:59 -0600371 if not build_targets:
372 return None
373
David Burger7fd1dbe2020-03-26 09:26:55 -0600374 result = {
375 'bcs-overlay': config.build_target.overlay_name,
376 'build-targets': build_targets,
David Burger7fd1dbe2020-03-26 09:26:55 -0600377 }
Andrew Lamb883fa042020-04-06 11:37:22 -0600378
David Burger8ee9b4d2020-06-16 17:40:21 -0600379 _upsert(main_ro.firmware_image_name.lower(), result, 'image-name')
Andrew Lamb883fa042020-04-06 11:37:22 -0600380
David Burger8ee9b4d2020-06-16 17:40:21 -0600381 _upsert(_fw_bcs_path(main_ro), result, 'main-ro-image')
382 _upsert(_fw_bcs_path(main_rw), result, 'main-rw-image')
383 _upsert(_fw_bcs_path(ec_ro), result, 'ec-ro-image')
384 _upsert(_fw_bcs_path(pd_ro), result, 'pd-ro-image')
David Burger7fd1dbe2020-03-26 09:26:55 -0600385
David Burger8ee9b4d2020-06-16 17:40:21 -0600386 _upsert(
Andrew Lambf39fbe82020-04-13 16:14:33 -0600387 config.hw_design_config.hardware_features.fw_config.value,
388 result,
389 'firmware-config',
390 )
391
David Burger7fd1dbe2020-03-26 09:26:55 -0600392 return result
393
394
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000395def _build_fw_signing(config, whitelabel):
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500396 if config.sw_config.firmware and config.device_signer_config:
David Burger68e0d142020-05-15 17:29:33 -0600397 hw_design = config.hw_design.name.lower()
Sam McNally2fc807f2020-07-16 18:13:53 +1000398 brand_scan_config = config.brand_config.scan_config
399 if brand_scan_config and brand_scan_config.whitelabel_tag:
400 signature_id = '%s-%s' % (hw_design, brand_scan_config.whitelabel_tag)
401 else:
402 signature_id = hw_design
403
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000404 result = {
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500405 'key-id': config.device_signer_config.key_id,
Sam McNally2fc807f2020-07-16 18:13:53 +1000406 'signature-id': signature_id,
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500407 }
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000408 if whitelabel:
409 result['sig-id-in-customization-id'] = True
410 return result
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500411 return {}
David Burger7fd1dbe2020-03-26 09:26:55 -0600412
413
Andrew Lambcd33f702020-06-11 10:45:16 -0600414def _file(source, destination):
Andrew Lamb2413c982020-05-29 12:15:36 -0600415 return {'destination': destination, 'source': source}
David Burger7fd1dbe2020-03-26 09:26:55 -0600416
417
David Burger40dfe3a2020-06-18 17:09:13 -0600418def _file_v2(build_path, system_path):
419 return {'build-path': build_path, 'system-path': system_path}
420
421
Andrew Lambcd33f702020-06-11 10:45:16 -0600422def _build_audio(config):
David Burger178f3ef2020-06-26 12:11:57 -0600423 if not config.sw_config.audio_configs:
424 return {}
David Burger7fd1dbe2020-03-26 09:26:55 -0600425 alsa_path = '/usr/share/alsa/ucm'
426 cras_path = '/etc/cras'
427 project_name = config.hw_design.name.lower()
David Burger43250662020-05-07 11:21:50 -0600428 program_name = config.program.name.lower()
David Burger7fd1dbe2020-03-26 09:26:55 -0600429 files = []
David Burger178f3ef2020-06-26 12:11:57 -0600430 ucm_suffix = None
431 for audio in config.sw_config.audio_configs:
432 card = audio.card_name
433 card_with_suffix = audio.card_name
434 if audio.ucm_suffix:
435 # TODO: last ucm_suffix wins.
436 ucm_suffix = audio.ucm_suffix
437 card_with_suffix += '.' + audio.ucm_suffix
438 if audio.ucm_file:
439 files.append(
440 _file(audio.ucm_file,
441 '%s/%s/HiFi.conf' % (alsa_path, card_with_suffix)))
442 if audio.ucm_master_file:
443 files.append(
444 _file(
445 audio.ucm_master_file, '%s/%s/%s.conf' %
Andrew Lamb2413c982020-05-29 12:15:36 -0600446 (alsa_path, card_with_suffix, card_with_suffix)))
David Burger178f3ef2020-06-26 12:11:57 -0600447 if audio.card_config_file:
448 files.append(
449 _file(audio.card_config_file,
450 '%s/%s/%s' % (cras_path, project_name, card)))
451 if audio.dsp_file:
452 files.append(
453 _file(audio.dsp_file, '%s/%s/dsp.ini' % (cras_path, project_name)))
454 if audio.module_file:
455 files.append(
456 _file(audio.module_file,
457 '/etc/modprobe.d/alsa-%s.conf' % program_name))
458 if audio.board_file:
459 files.append(
460 _file(audio.board_file,
461 '%s/%s/board.ini' % (cras_path, project_name)))
David Burger599ff7b2020-04-06 16:29:31 -0600462
463 result = {
David Burger7fd1dbe2020-03-26 09:26:55 -0600464 'main': {
465 'cras-config-dir': project_name,
466 'files': files,
467 }
468 }
David Burger178f3ef2020-06-26 12:11:57 -0600469
470 if ucm_suffix:
471 result['main']['ucm-suffix'] = ucm_suffix
David Burger599ff7b2020-04-06 16:29:31 -0600472
473 return result
David Burger7fd1dbe2020-03-26 09:26:55 -0600474
475
Andrew Lambcd33f702020-06-11 10:45:16 -0600476def _build_camera(hw_topology):
Ren-Pei Zeng573d6332020-11-12 14:55:22 +0800477 camera_pb = topology_pb2.HardwareFeatures.Camera
478 camera = hw_topology.camera.hardware_feature.camera
479 result = {'count': len(camera.devices)}
480 if camera.devices:
481 result['devices'] = []
482 for device in camera.devices:
483 interface = {
484 camera_pb.INTERFACE_USB: 'usb',
485 camera_pb.INTERFACE_MIPI: 'mipi',
486 }[device.interface]
487 facing = {
488 camera_pb.FACING_FRONT: 'front',
489 camera_pb.FACING_BACK: 'back',
490 }[device.facing]
491 orientation = {
492 camera_pb.ORIENTATION_0: 0,
493 camera_pb.ORIENTATION_90: 90,
494 camera_pb.ORIENTATION_180: 180,
495 camera_pb.ORIENTATION_270: 270,
496 }[device.orientation]
497 flags = {
498 'support-1080p':
499 bool(device.flags & camera_pb.FLAGS_SUPPORT_1080P),
500 'support-autofocus':
501 bool(device.flags & camera_pb.FLAGS_SUPPORT_AUTOFOCUS),
502 }
503 result['devices'].append({
504 'interface': interface,
505 'facing': facing,
506 'orientation': orientation,
507 'flags': flags,
508 'ids': list(device.ids),
509 })
510 return result
David Burger8aa8fa32020-04-14 08:30:34 -0600511
Andrew Lambcd33f702020-06-11 10:45:16 -0600512
513def _build_identity(hw_scan_config, program, brand_scan_config=None):
David Burger7fd1dbe2020-03-26 09:26:55 -0600514 identity = {}
David Burger8ee9b4d2020-06-16 17:40:21 -0600515 _upsert(hw_scan_config.firmware_sku, identity, 'sku-id')
516 _upsert(hw_scan_config.smbios_name_match, identity, 'smbios-name-match')
Andrew Lamb7806ce92020-04-07 10:22:17 -0600517 # 'platform-name' is needed to support 'mosys platform name'. Clients should
Sean McAllister0b757772020-11-13 12:22:36 -0700518 # no longer require platform name, but set it here for backwards compatibility.
519 if program.mosys_platform_name:
520 _upsert(program.mosys_platform_name, identity, 'platform-name')
521 else:
522 _upsert(program.name, identity, 'platform-name')
523
David Burger7fd1dbe2020-03-26 09:26:55 -0600524 # ARM architecture
David Burger8ee9b4d2020-06-16 17:40:21 -0600525 _upsert(hw_scan_config.device_tree_compatible_match, identity,
526 'device-tree-compatible-match')
David Burger7fd1dbe2020-03-26 09:26:55 -0600527
528 if brand_scan_config:
David Burger8ee9b4d2020-06-16 17:40:21 -0600529 _upsert(brand_scan_config.whitelabel_tag, identity, 'whitelabel-tag')
David Burger7fd1dbe2020-03-26 09:26:55 -0600530
531 return identity
532
533
Andrew Lambcd33f702020-06-11 10:45:16 -0600534def _lookup(id_value, id_map):
535 if not id_value.value:
536 return None
537
538 key = id_value.value
539 if key in id_map:
540 return id_map[id_value.value]
541 error = 'Failed to lookup %s with value: %s' % (
542 id_value.__class__.__name__.replace('Id', ''), key)
543 print(error)
544 print('Check the config contents provided:')
545 printer = pprint.PrettyPrinter(indent=4)
546 printer.pprint(id_map)
547 raise Exception(error)
David Burger7fd1dbe2020-03-26 09:26:55 -0600548
549
Andrew Lambcd33f702020-06-11 10:45:16 -0600550def _build_touch_file_config(config, project_name):
Sean McAllistereaf10b72020-08-03 13:41:06 -0600551 partners = {x.id.value: x for x in config.partner_list}
C Shapiro2b6d5332020-05-06 17:51:35 -0500552 files = []
553 for comp in config.components:
C Shapiro4813be62020-05-13 17:31:58 -0500554 touch = comp.touchscreen
555 # Everything is the same for Touch screen/pad, except different fields
556 if comp.HasField('touchpad'):
557 touch = comp.touchpad
558 if touch.product_id:
Andrew Lambcd33f702020-06-11 10:45:16 -0600559 vendor = _lookup(comp.manufacturer_id, partners)
C Shapiro2b6d5332020-05-06 17:51:35 -0500560 if not vendor:
Andrew Lamb2413c982020-05-29 12:15:36 -0600561 raise Exception("Manufacturer must be set for touch device %s" %
562 comp.id.value)
C Shapiro2b6d5332020-05-06 17:51:35 -0500563
C Shapiro4813be62020-05-13 17:31:58 -0500564 product_id = touch.product_id
565 fw_version = touch.fw_version
C Shapiro2b6d5332020-05-06 17:51:35 -0500566
C Shapiro2b6d5332020-05-06 17:51:35 -0500567 file_name = "%s_%s.bin" % (product_id, fw_version)
568 fw_file_path = os.path.join(TOUCH_PATH, vendor.name, file_name)
569
570 if not os.path.exists(fw_file_path):
Andrew Lamb2413c982020-05-29 12:15:36 -0600571 raise Exception("Touchscreen fw bin file doesn't exist at: %s" %
572 fw_file_path)
C Shapiro2b6d5332020-05-06 17:51:35 -0500573
C Shapiro303cece2020-07-22 07:15:21 -0500574 touch_vendor = vendor.touch_vendor
575 sym_link = touch_vendor.symlink_file_format.format(
576 vendor_name=vendor.name,
577 vendor_id=touch_vendor.vendor_id,
578 product_id=product_id,
579 fw_version=fw_version,
580 product_series=touch.product_series)
581
582 dest = "%s_%s" % (vendor.name, file_name)
583 if touch_vendor.destination_file_format:
584 dest = touch_vendor.destination_file_format.format(
585 vendor_name=vendor.name,
586 vendor_id=touch_vendor.vendor_id,
587 product_id=product_id,
588 fw_version=fw_version,
589 product_series=touch.product_series)
590
C Shapiro2b6d5332020-05-06 17:51:35 -0500591 files.append({
C Shapiro303cece2020-07-22 07:15:21 -0500592 "destination": os.path.join("/opt/google/touch/firmware", dest),
YH Lin9160fc52020-07-22 16:35:28 -0700593 "source": os.path.join(project_name, fw_file_path),
594 "symlink": os.path.join("/lib/firmware", sym_link),
C Shapiro2b6d5332020-05-06 17:51:35 -0500595 })
596
597 result = {}
David Burger8ee9b4d2020-06-16 17:40:21 -0600598 _upsert(files, result, 'files')
C Shapiro2b6d5332020-05-06 17:51:35 -0500599 return result
600
601
David Burgerceeb68a2020-09-03 11:31:10 -0600602def _sw_config(sw_configs, design_config_id):
603 """Returns the correct software config for `design_config_id`.
604
605 Returns the correct software config match for `design_config_id`. If no such
606 config or multiple such configs are found an exception is raised.
607 """
608 sw_config_matches = [
609 x for x in sw_configs if x.design_config_id.value == design_config_id
610 ]
611 if len(sw_config_matches) == 1:
612 return sw_config_matches[0]
613 if len(sw_config_matches) > 1:
614 raise ValueError('Multiple software configs found for: %s' %
615 design_config_id)
616 raise ValueError('Software config is required for: %s' % design_config_id)
617
618
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000619def _is_whitelabel(brand_configs, device_brands):
620 for device_brand in device_brands:
621 if device_brand.id.value in brand_configs:
622 brand_scan_config = brand_configs[device_brand.id.value].scan_config
623 if brand_scan_config and brand_scan_config.whitelabel_tag:
624 return True
625 return False
626
627
David Burgerceeb68a2020-09-03 11:31:10 -0600628def _transform_build_configs(config,
629 config_files=ConfigFiles({}, {}, {}, {}, {})):
Andrew Lambcd33f702020-06-11 10:45:16 -0600630 # pylint: disable=too-many-locals,too-many-branches
Sean McAllistereaf10b72020-08-03 13:41:06 -0600631 partners = {x.id.value: x for x in config.partner_list}
Sean McAllisterf38d1e92020-08-03 13:57:53 -0600632 programs = {x.id.value: x for x in config.program_list}
David Burger7fd1dbe2020-03-26 09:26:55 -0600633 sw_configs = list(config.software_configs)
Andrew Lambcd33f702020-06-11 10:45:16 -0600634 brand_configs = {x.brand_id.value: x for x in config.brand_configs}
David Burger7fd1dbe2020-03-26 09:26:55 -0600635
C Shapiroa0b766c2020-03-31 08:35:28 -0500636 if len(config.build_targets) != 1:
637 # Artifact of sharing the config_bundle for analysis and transforms.
638 # Integrated analysis of multiple programs/projects it the only time
639 # having multiple build targets would be valid.
640 raise Exception('Single build_target required for transform')
641
David Burger7fd1dbe2020-03-26 09:26:55 -0600642 results = {}
Sean McAllisterf66887b2020-08-03 14:00:51 -0600643 for hw_design in config.design_list:
Sean McAllister6cbb0ec2020-08-03 14:03:37 -0600644 if config.device_brand_list:
Andrew Lamb2413c982020-05-29 12:15:36 -0600645 device_brands = [
Sean McAllister6cbb0ec2020-08-03 14:03:37 -0600646 x for x in config.device_brand_list
Andrew Lamb2413c982020-05-29 12:15:36 -0600647 if x.design_id.value == hw_design.id.value
648 ]
David Burger7fd1dbe2020-03-26 09:26:55 -0600649 else:
650 device_brands = [device_brand_pb2.DeviceBrand()]
651
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000652 whitelabel = _is_whitelabel(brand_configs, device_brands)
653
David Burger7fd1dbe2020-03-26 09:26:55 -0600654 for device_brand in device_brands:
655 # Brand config can be empty since platform JSON config allows it
656 brand_config = brand_config_pb2.BrandConfig()
657 if device_brand.id.value in brand_configs:
658 brand_config = brand_configs[device_brand.id.value]
659
660 for hw_design_config in hw_design.configs:
David Burgerceeb68a2020-09-03 11:31:10 -0600661 sw_config = _sw_config(sw_configs, hw_design_config.id.value)
Andrew Lambcd33f702020-06-11 10:45:16 -0600662 program = _lookup(hw_design.program_id, programs)
C Shapiroadefd7c2020-05-19 16:37:21 -0500663 signer_configs_by_design = {}
664 signer_configs_by_brand = {}
665 for signer_config in program.device_signer_configs:
666 design_id = signer_config.design_id.value
667 brand_id = signer_config.brand_id.value
668 if design_id:
669 signer_configs_by_design[design_id] = signer_config
670 elif brand_id:
671 signer_configs_by_brand[brand_id] = signer_config
672 else:
673 raise Exception('No ID found for signer config: %s' % signer_config)
674
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500675 device_signer_config = None
C Shapiroadefd7c2020-05-19 16:37:21 -0500676 if signer_configs_by_design or signer_configs_by_brand:
677 design_id = hw_design.id.value
678 brand_id = device_brand.id.value
679 if design_id in signer_configs_by_design:
680 device_signer_config = signer_configs_by_design[design_id]
681 elif brand_id in signer_configs_by_brand:
682 device_signer_config = signer_configs_by_brand[brand_id]
683 else:
684 # Assume that if signer configs are set, every config is setup
Andrew Lamb2413c982020-05-29 12:15:36 -0600685 raise Exception('Signer config missing for design: %s, brand: %s' %
686 (design_id, brand_id))
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500687
Andrew Lambcd33f702020-06-11 10:45:16 -0600688 transformed_config = _transform_build_config(
C Shapiro90fda252020-04-17 14:34:57 -0500689 Config(
690 program=program,
691 hw_design=hw_design,
Andrew Lambcd33f702020-06-11 10:45:16 -0600692 odm=_lookup(hw_design.odm_id, partners),
C Shapiro90fda252020-04-17 14:34:57 -0500693 hw_design_config=hw_design_config,
694 device_brand=device_brand,
695 device_signer_config=device_signer_config,
Andrew Lambcd33f702020-06-11 10:45:16 -0600696 oem=_lookup(device_brand.oem_id, partners),
C Shapiro90fda252020-04-17 14:34:57 -0500697 sw_config=sw_config,
698 brand_config=brand_config,
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000699 build_target=config.build_targets[0]), config_files, whitelabel)
David Burger7fd1dbe2020-03-26 09:26:55 -0600700
Andrew Lamb2413c982020-05-29 12:15:36 -0600701 config_json = json.dumps(
702 transformed_config,
703 sort_keys=True,
704 indent=2,
705 separators=(',', ': '))
David Burger7fd1dbe2020-03-26 09:26:55 -0600706
707 if config_json not in results:
708 results[config_json] = transformed_config
709
710 return list(results.values())
711
712
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000713def _transform_build_config(config, config_files, whitelabel):
David Burger7fd1dbe2020-03-26 09:26:55 -0600714 """Transforms Config instance into target platform JSON schema.
715
716 Args:
717 config: Config namedtuple
C Shapiro5bf23a72020-04-24 11:40:17 -0500718 config_files: Map to look up the generated config files.
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000719 whitelabel: Whether the config is for a whitelabel design
David Burger7fd1dbe2020-03-26 09:26:55 -0600720
721 Returns:
722 Unique config payload based on the platform JSON schema.
723 """
724 result = {
Andrew Lamb2413c982020-05-29 12:15:36 -0600725 'identity':
Andrew Lambcd33f702020-06-11 10:45:16 -0600726 _build_identity(config.sw_config.id_scan_config, config.program,
727 config.brand_config.scan_config),
Andrew Lamb2413c982020-05-29 12:15:36 -0600728 'name':
729 config.hw_design.name.lower(),
David Burger7fd1dbe2020-03-26 09:26:55 -0600730 }
731
David Burger8ee9b4d2020-06-16 17:40:21 -0600732 _upsert(_build_arc(config, config_files), result, 'arc')
733 _upsert(_build_audio(config), result, 'audio')
David Burger07af5242020-08-11 11:08:25 -0600734 _upsert(_build_bluetooth(config), result, 'bluetooth')
David Burgerceeb68a2020-09-03 11:31:10 -0600735 _upsert(_build_wifi(config, config_files), result, 'wifi')
Andrew Lambca279902020-08-06 10:13:42 -0600736 _upsert(config.brand_config.wallpaper, result, 'wallpaper')
C Shapiro2e97aad2020-11-16 11:58:10 -0600737 _upsert(config.brand_config.regulatory_label, result, 'regulatory-label')
David Burger8ee9b4d2020-06-16 17:40:21 -0600738 _upsert(config.device_brand.brand_code, result, 'brand-code')
739 _upsert(
Andrew Lambcd33f702020-06-11 10:45:16 -0600740 _build_camera(config.hw_design_config.hardware_topology), result,
741 'camera')
David Burger8ee9b4d2020-06-16 17:40:21 -0600742 _upsert(_build_firmware(config), result, 'firmware')
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000743 _upsert(_build_fw_signing(config, whitelabel), result, 'firmware-signing')
David Burger8ee9b4d2020-06-16 17:40:21 -0600744 _upsert(
Andrew Lambcd33f702020-06-11 10:45:16 -0600745 _build_fingerprint(config.hw_design_config.hardware_topology), result,
Andrew Lamb2413c982020-05-29 12:15:36 -0600746 'fingerprint')
Andrew Lamb0d236ab2020-06-30 12:30:20 -0600747 _upsert(_build_ui(config), result, 'ui')
David Burger7fd1dbe2020-03-26 09:26:55 -0600748 power_prefs = config.sw_config.power_config.preferences
749 power_prefs_map = dict(
Andrew Lamb2413c982020-05-29 12:15:36 -0600750 (x.replace('_', '-'), power_prefs[x]) for x in power_prefs)
David Burger8ee9b4d2020-06-16 17:40:21 -0600751 _upsert(power_prefs_map, result, 'power')
752 if config_files.camera_map:
753 camera_file = config_files.camera_map.get(config.hw_design.name, {})
754 _upsert(camera_file, result, 'camera')
David Burger52c9d322020-06-09 07:16:18 -0600755 if config_files.dptf_map:
756 # Prefer design specific if found, if not fall back to project wide config
757 # mapped under the empty string.
758 if config_files.dptf_map.get(config.hw_design.name):
759 dptf_file = config_files.dptf_map[config.hw_design.name]
760 else:
761 dptf_file = config_files.dptf_map.get('')
David Burger8ee9b4d2020-06-16 17:40:21 -0600762 _upsert(dptf_file, result, 'thermal')
763 _upsert(config_files.touch_fw, result, 'touch')
Trent Beginf067ccb2020-08-12 12:33:53 -0600764 _upsert(
765 _build_hardware_properties(config.hw_design_config.hardware_topology),
766 result, 'hardware-properties')
David Burger7fd1dbe2020-03-26 09:26:55 -0600767
768 return result
769
770
Andrew Lambcd33f702020-06-11 10:45:16 -0600771def write_output(configs, output=None):
David Burger7fd1dbe2020-03-26 09:26:55 -0600772 """Writes a list of configs to platform JSON format.
773
774 Args:
775 configs: List of config dicts defined in cros_config_schema.yaml
776 output: Target file output (if None, prints to stdout)
777 """
Andrew Lamb2413c982020-05-29 12:15:36 -0600778 json_output = json.dumps({'chromeos': {
779 'configs': configs,
780 }},
781 sort_keys=True,
782 indent=2,
783 separators=(',', ': '))
David Burger7fd1dbe2020-03-26 09:26:55 -0600784 if output:
785 with open(output, 'w') as output_stream:
786 # Using print function adds proper trailing newline.
787 print(json_output, file=output_stream)
788 else:
789 print(json_output)
790
791
Andrew Lambcd33f702020-06-11 10:45:16 -0600792def _feature(name, present):
C Shapiro5bf23a72020-04-24 11:40:17 -0500793 attrib = {'name': name}
794 if present:
795 return etree.Element('feature', attrib=attrib)
Andrew Lambcd33f702020-06-11 10:45:16 -0600796
797 return etree.Element('unavailable-feature', attrib=attrib)
C Shapiro5bf23a72020-04-24 11:40:17 -0500798
799
Andrew Lambcd33f702020-06-11 10:45:16 -0600800def _any_present(features):
Andrew Lamb2413c982020-05-29 12:15:36 -0600801 return topology_pb2.HardwareFeatures.PRESENT in features
C Shapiro5bf23a72020-04-24 11:40:17 -0500802
803
Andrew Lambcd33f702020-06-11 10:45:16 -0600804def _arc_hardware_feature_id(design_config):
C Shapiro5bf23a72020-04-24 11:40:17 -0500805 return design_config.id.value.lower().replace(':', '_')
806
807
Andrew Lambcd33f702020-06-11 10:45:16 -0600808def _write_arc_hardware_feature_file(output_dir, file_name, config_content):
David Burger77a1d312020-05-23 16:05:45 -0600809 output_dir += '/arc'
810 os.makedirs(output_dir, exist_ok=True)
811 output = '%s/%s' % (output_dir, file_name)
Andrew Lamb2413c982020-05-29 12:15:36 -0600812 file_content = minidom.parseString(config_content).toprettyxml(
813 indent=' ', encoding='utf-8')
C Shapiroea33cff2020-05-11 13:32:05 -0500814
815 with open(output, 'wb') as f:
816 f.write(file_content)
817
818
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800819def _get_arc_camera_features(camera):
820 """Gets camera related features for ARC hardware_features.xml from camera
821 topology. Check
822 https://developer.android.com/reference/android/content/pm/PackageManager#FEATURE_CAMERA
823 and CTS android.app.cts.SystemFeaturesTest#testCameraFeatures for the correct
824 settings.
825
826 Args:
827 camera: A HardwareFeatures.Camera proto message.
828 Returns:
829 list of camera related ARC features as XML elements.
830 """
831 camera_pb = topology_pb2.HardwareFeatures.Camera
832
Ren-Pei Zeng9b5682d2020-10-14 17:37:30 +0800833 count = len(camera.devices)
834 has_front_camera = any(
835 (d.facing == camera_pb.FACING_FRONT for d in camera.devices))
836 has_back_camera = any(
837 (d.facing == camera_pb.FACING_BACK for d in camera.devices))
838 has_autofocus_back_camera = any((d.facing == camera_pb.FACING_BACK and
839 d.flags & camera_pb.FLAGS_SUPPORT_AUTOFOCUS
840 for d in camera.devices))
841 # Assumes MIPI cameras support FULL-level.
842 # TODO(kamesan): Setting this in project configs when there's an exception.
843 has_level_full_camera = any(
844 (d.interface == camera_pb.INTERFACE_MIPI for d in camera.devices))
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800845
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800846 return [
847 _feature('android.hardware.camera', has_back_camera),
848 _feature('android.hardware.camera.any', count > 0),
849 _feature('android.hardware.camera.autofocus', has_autofocus_back_camera),
850 _feature('android.hardware.camera.capability.manual_post_processing',
851 has_level_full_camera),
852 _feature('android.hardware.camera.capability.manual_sensor',
853 has_level_full_camera),
854 _feature('android.hardware.camera.front', has_front_camera),
855 _feature('android.hardware.camera.level.full', has_level_full_camera),
856 ]
857
858
Andrew Lambcd33f702020-06-11 10:45:16 -0600859def _write_arc_hardware_feature_files(config, output_dir, build_root_dir):
C Shapiro5bf23a72020-04-24 11:40:17 -0500860 """Writes ARC hardware_feature.xml files for each config
861
862 Args:
863 config: Source ConfigBundle to process.
864 output_dir: Path to the generated output.
C Shapiro5c877992020-04-29 12:11:28 -0500865 build_root_path: Path to the config file from portage's perspective.
C Shapiro5bf23a72020-04-24 11:40:17 -0500866 Returns:
867 dict that maps the design_config_id onto the correct file.
868 """
Andrew Lambcd33f702020-06-11 10:45:16 -0600869 # pylint: disable=too-many-locals
C Shapiro5bf23a72020-04-24 11:40:17 -0500870 result = {}
C Shapiroea33cff2020-05-11 13:32:05 -0500871 configs_by_design = {}
Sean McAllisterf66887b2020-08-03 14:00:51 -0600872 for hw_design in config.design_list:
C Shapiro5bf23a72020-04-24 11:40:17 -0500873 for design_config in hw_design.configs:
874 hw_features = design_config.hardware_features
Andrew Lambcd33f702020-06-11 10:45:16 -0600875 touchscreen = _any_present([hw_features.screen.touch_support])
C Shapiro5bf23a72020-04-24 11:40:17 -0500876 acc = hw_features.accelerometer
877 gyro = hw_features.gyroscope
878 compass = hw_features.magnetometer
Andrew Lambcd33f702020-06-11 10:45:16 -0600879 light_sensor = hw_features.light_sensor
C Shapiro5bf23a72020-04-24 11:40:17 -0500880 root = etree.Element('permissions')
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800881 root.extend(
882 _get_arc_camera_features(hw_features.camera) + [
883 _feature(
884 'android.hardware.sensor.accelerometer',
885 _any_present([acc.lid_accelerometer, acc.base_accelerometer
886 ])),
887 _feature('android.hardware.sensor.gyroscope',
888 _any_present([gyro.lid_gyroscope, gyro.base_gyroscope])),
889 _feature(
890 'android.hardware.sensor.compass',
891 _any_present(
892 [compass.lid_magnetometer, compass.base_magnetometer])),
893 _feature(
894 'android.hardware.sensor.light',
895 _any_present([
896 light_sensor.lid_lightsensor,
897 light_sensor.base_lightsensor
898 ])),
899 _feature('android.hardware.touchscreen', touchscreen),
900 _feature('android.hardware.touchscreen.multitouch', touchscreen),
901 _feature('android.hardware.touchscreen.multitouch.distinct',
902 touchscreen),
903 _feature('android.hardware.touchscreen.multitouch.jazzhand',
904 touchscreen),
905 ])
C Shapiro5bf23a72020-04-24 11:40:17 -0500906
C Shapiroea33cff2020-05-11 13:32:05 -0500907 design_name = hw_design.name.lower()
C Shapiro5bf23a72020-04-24 11:40:17 -0500908
C Shapiroea33cff2020-05-11 13:32:05 -0500909 # Constructs the following map:
910 # design_name -> config -> design_configs
911 # This allows any of the following file naming schemes:
912 # - All configs within a design share config (design_name prefix only)
913 # - Nobody shares (full design_name and config id prefix needed)
914 #
915 # Having shared configs when possible makes code reviews easier around
916 # the configs and makes debugging easier on the platform side.
917 config_content = etree.tostring(root)
918 arc_configs = configs_by_design.get(design_name, {})
919 design_configs = arc_configs.get(config_content, [])
920 design_configs.append(design_config)
921 arc_configs[config_content] = design_configs
922 configs_by_design[design_name] = arc_configs
C Shapiro9a3ac8c2020-04-25 07:49:21 -0500923
C Shapiroea33cff2020-05-11 13:32:05 -0500924 for design_name, unique_configs in configs_by_design.items():
925 for file_content, design_configs in unique_configs.items():
Andrew Lamb2413c982020-05-29 12:15:36 -0600926 file_name = 'hardware_features_%s.xml' % design_name
927 if len(unique_configs) == 1:
Andrew Lambcd33f702020-06-11 10:45:16 -0600928 _write_arc_hardware_feature_file(output_dir, file_name, file_content)
C Shapiro9a3ac8c2020-04-25 07:49:21 -0500929
Andrew Lamb2413c982020-05-29 12:15:36 -0600930 for design_config in design_configs:
Andrew Lambcd33f702020-06-11 10:45:16 -0600931 feature_id = _arc_hardware_feature_id(design_config)
Andrew Lamb2413c982020-05-29 12:15:36 -0600932 if len(unique_configs) > 1:
933 file_name = 'hardware_features_%s.xml' % feature_id
Andrew Lambcd33f702020-06-11 10:45:16 -0600934 _write_arc_hardware_feature_file(output_dir, file_name, file_content)
David Burger40dfe3a2020-06-18 17:09:13 -0600935 result[feature_id] = _file_v2('%s/arc/%s' % (build_root_dir, file_name),
936 '/etc/%s' % file_name)
C Shapiro5bf23a72020-04-24 11:40:17 -0500937 return result
938
939
Andrew Lambcd33f702020-06-11 10:45:16 -0600940def _read_config(path):
David Burgerd4f32962020-05-02 12:07:40 -0600941 """Reads a ConfigBundle proto from a json pb file.
David Burgere6f76222020-04-27 11:08:01 -0600942
943 Args:
David Burgerd4f32962020-05-02 12:07:40 -0600944 path: Path to the file encoding the json pb proto.
David Burgere6f76222020-04-27 11:08:01 -0600945 """
946 config = config_bundle_pb2.ConfigBundle()
947 with open(path, 'r') as f:
948 return json_format.Parse(f.read(), config)
949
950
Andrew Lambcd33f702020-06-11 10:45:16 -0600951def _merge_configs(configs):
David Burger7fd1dbe2020-03-26 09:26:55 -0600952 result = config_bundle_pb2.ConfigBundle()
953 for config in configs:
954 result.MergeFrom(config)
955
956 return result
957
958
David Burger1ba78a22020-06-18 18:42:47 -0600959def _camera_map(configs, project_name):
David Burger8ee9b4d2020-06-16 17:40:21 -0600960 """Produces a camera config map for the given configs.
961
962 Produces a map that maps from the design name to the camera config for that
963 design.
964
965 Args:
966 configs: Source ConfigBundle to process.
David Burger1ba78a22020-06-18 18:42:47 -0600967 project_name: Name of project processing for.
David Burger8ee9b4d2020-06-16 17:40:21 -0600968
969 Returns:
970 map from design name to camera config.
971 """
972 result = {}
Sean McAllisterf66887b2020-08-03 14:00:51 -0600973 for design in configs.design_list:
David Burger8ee9b4d2020-06-16 17:40:21 -0600974 design_name = design.name
David Burger0d9e8462020-06-19 14:12:37 -0600975 config_path = CAMERA_CONFIG_SOURCE_PATH_TEMPLATE.format(design_name.lower())
David Burger8ee9b4d2020-06-16 17:40:21 -0600976 if os.path.exists(config_path):
David Burger0d9e8462020-06-19 14:12:37 -0600977 destination = CAMERA_CONFIG_DEST_PATH_TEMPLATE.format(design_name.lower())
David Burger8ee9b4d2020-06-16 17:40:21 -0600978 result[design_name] = {
David Burger1ba78a22020-06-18 18:42:47 -0600979 'config-file':
980 _file_v2(os.path.join(project_name, config_path), destination),
David Burger8ee9b4d2020-06-16 17:40:21 -0600981 }
982 return result
983
984
David Burger52c9d322020-06-09 07:16:18 -0600985def _dptf_map(configs, project_name):
986 """Produces a dptf map for the given configs.
987
988 Produces a map that maps from design name to the dptf file config for that
989 design. It looks for the dptf files at:
David Burger2f0d9522020-07-30 10:52:28 -0600990 DPTF_PATH + '/' + DPTF_FILE
David Burger52c9d322020-06-09 07:16:18 -0600991 for a project wide config, that it maps under the empty string, and at:
David Burger2f0d9522020-07-30 10:52:28 -0600992 DPTF_PATH + '/' + design_name + '/' + DPTF_FILE
David Burger52c9d322020-06-09 07:16:18 -0600993 for design specific configs that it maps under the design name.
994
995 Args:
996 configs: Source ConfigBundle to process.
997 project_name: Name of project processing for.
998
999 Returns:
David Burger8ee9b4d2020-06-16 17:40:21 -06001000 map from design name or empty string (project wide), to dptf config.
David Burger52c9d322020-06-09 07:16:18 -06001001 """
1002 result = {}
David Burger52c9d322020-06-09 07:16:18 -06001003 # Looking at top level for project wide, and then for each design name
1004 # for design specific.
Sean McAllisterf66887b2020-08-03 14:00:51 -06001005 dirs = [""] + [d.name for d in configs.design_list]
David Burger52c9d322020-06-09 07:16:18 -06001006 for directory in dirs:
David Burgera2252762020-07-09 15:09:49 -06001007 design = directory.lower()
1008 if os.path.exists(os.path.join(DPTF_PATH, design, DPTF_FILE)):
David Burger2f0d9522020-07-30 10:52:28 -06001009 project_dptf_path = os.path.join(project_name, design, DPTF_FILE)
David Burger52c9d322020-06-09 07:16:18 -06001010 dptf_file = {
1011 'dptf-dv':
1012 project_dptf_path,
1013 'files': [
1014 _file(
David Burgera2252762020-07-09 15:09:49 -06001015 os.path.join(project_name, DPTF_PATH, design, DPTF_FILE),
David Burger52c9d322020-06-09 07:16:18 -06001016 os.path.join('/etc/dptf', project_dptf_path))
1017 ]
1018 }
1019 result[directory] = dptf_file
1020 return result
1021
1022
David Burgerceeb68a2020-09-03 11:31:10 -06001023def _wifi_sar_map(configs, project_name, output_dir, build_root_dir):
1024 """Constructs a map from design name to wifi sar config for that design.
1025
1026 Constructs a map from design name to the wifi sar config for that design.
1027 In the process a wifi sar hex file is generated that the config points at.
1028 This mapping is only made for the intel wifi where the generated file is
1029 provided when building coreboot.
1030
1031 Args:
1032 configs: Source ConfigBundle to process.
1033 project_name: Name of project processing for.
1034 output_dir: Path to the generated output.
1035 build_root_path: Path to the config file from portage's perspective.
1036
1037 Returns:
1038 dict that maps the design name onto the wifi config for that design.
1039 """
1040 # pylint: disable=too-many-locals
1041 result = {}
1042 programs = {p.id.value: p for p in configs.program_list}
1043 sw_configs = list(configs.software_configs)
1044 for hw_design in configs.design_list:
1045 for hw_design_config in hw_design.configs:
1046 sw_config = _sw_config(sw_configs, hw_design_config.id.value)
1047 if sw_config.wifi_config.HasField('intel_config'):
1048 sar_file_content = _create_intel_sar_file_content(
1049 sw_config.wifi_config.intel_config)
1050 design_name = hw_design.name.lower()
1051 program = _lookup(hw_design.program_id, programs)
1052 wifi_sar_id = _extract_fw_config_value(hw_design_config, program,
1053 'Intel wifi sar id')
1054 output_path = os.path.join(output_dir, 'wifi')
1055 os.makedirs(output_path, exist_ok=True)
1056 filename = 'wifi_sar_{}.hex'.format(wifi_sar_id)
1057 output_path = os.path.join(output_path, filename)
1058 build_path = os.path.join(build_root_dir, 'wifi', filename)
1059 if os.path.exists(output_path):
1060 with open(output_path, 'r') as f:
1061 if f.read() != sar_file_content:
1062 raise Exception(
1063 'Project {} has conflicting wifi sar file content under '
1064 'wifi sar id {}.'.format(project_name, wifi_sar_id))
1065 else:
1066 with open(output_path, 'w') as f:
1067 f.write(sar_file_content)
1068 system_path = '/firmware/cbfs-rw-raw/{}/{}'.format(
1069 project_name, filename)
David Burger89e7cae2020-09-15 17:04:12 -06001070 result[design_name] = {'sar-file': _file_v2(build_path, system_path)}
David Burgerceeb68a2020-09-03 11:31:10 -06001071 return result
1072
1073
1074def _extract_fw_config_value(hw_design_config, program, name):
1075 """Extracts the firwmare config value with the given name.
1076
1077 Args:
1078 hw_design_config: Design extracting value from.
1079 program: Program the `hw_design_config` belongs to.
1080 name: Name of firmware config segment to extract.
1081
1082 Returns: the extracted value or raises a ValueError if no firmware
1083 configuration segment with `name` is found.
1084 """
1085 fw_config = hw_design_config.hardware_features.fw_config.value
1086 for fcs in program.firmware_configuration_segments:
1087 if fcs.name == name:
1088 value = fw_config & fcs.mask
1089 lsb_bit_set = (~fcs.mask + 1) & fcs.mask
1090 return value // lsb_bit_set
1091 raise ValueError(
1092 'No firmware configuration segment with name {} found'.format(name))
1093
1094
1095def _create_intel_sar_file_content(intel_config):
1096 """Creates and returns the intel sar file content for the given config.
1097
1098 Creates and returns the sar file content that is used with intel drivers
1099 only.
1100
1101 Args:
1102 intel_config: IntelConfig config.
1103
1104 Returns:
1105 sar file content for the given config, see:
1106 https://chromeos.google.com/partner/dlm/docs/connectivity/wifidyntxpower.html
1107 """
1108
1109 def to_hex(val):
1110 if val > 255 or val < 0:
1111 raise Exception('Sar file value %s out of range' % val)
1112 return '{0:0{1}X}'.format(val, 2)
1113
1114 def power_table(tpc):
1115 return (to_hex(tpc.limit_2g) + to_hex(tpc.limit_5g_1) +
1116 to_hex(tpc.limit_5g_2) + to_hex(tpc.limit_5g_3) +
1117 to_hex(tpc.limit_5g_4))
1118
1119 def wgds_value(wgds):
1120 return to_hex(wgds)
1121
1122 def offset_table(offsets):
1123 return (to_hex(offsets.max_2g) + to_hex(offsets.offset_2g_a) +
1124 to_hex(offsets.offset_2g_b) + to_hex(offsets.max_5g) +
1125 to_hex(offsets.offset_5g_a) + to_hex(offsets.offset_5g_b))
1126
1127 # See https://chromeos.google.com/partner/dlm/docs/connectivity/wifidyntxpower.html
1128 return (power_table(intel_config.tablet_mode_power_table_a) +
1129 power_table(intel_config.tablet_mode_power_table_b) +
1130 power_table(intel_config.non_tablet_mode_power_table_a) +
1131 power_table(intel_config.non_tablet_mode_power_table_b) +
1132 '00000000000000000000' + '00000000000000000000' +
1133 wgds_value(intel_config.wgds_version) +
1134 offset_table(intel_config.offset_fcc) +
1135 offset_table(intel_config.offset_eu) +
1136 offset_table(intel_config.offset_other))
1137
1138
Andrew Lambcd33f702020-06-11 10:45:16 -06001139def Main(project_configs, program_config, output): # pylint: disable=invalid-name
David Burger7fd1dbe2020-03-26 09:26:55 -06001140 """Transforms source proto config into platform JSON.
1141
1142 Args:
1143 project_configs: List of source project configs to transform.
1144 program_config: Program config for the given set of projects.
1145 output: Output file that will be generated by the transform.
1146 """
Andrew Lambcd33f702020-06-11 10:45:16 -06001147 configs = _merge_configs([_read_config(program_config)] +
1148 [_read_config(config) for config in project_configs])
C Shapiro5bf23a72020-04-24 11:40:17 -05001149 arc_hw_feature_files = {}
C Shapiro2b6d5332020-05-06 17:51:35 -05001150 touch_fw = {}
David Burger8ee9b4d2020-06-16 17:40:21 -06001151 camera_map = {}
David Burgerceeb68a2020-09-03 11:31:10 -06001152 dptf_map = {}
1153 wifi_sar_map = {}
C Shapiro5bf23a72020-04-24 11:40:17 -05001154 output_dir = os.path.dirname(output)
C Shapiro5c877992020-04-29 12:11:28 -05001155 build_root_dir = output_dir
C Shapiro5c877992020-04-29 12:11:28 -05001156 if 'sw_build_config' in output_dir:
1157 full_path = os.path.realpath(output)
Andrew Lamb6b607732020-08-24 15:52:46 -06001158 project_name = re.match(r'.*/(\w*)/(public_)?sw_build_config/.*',
Andrew Lamb2413c982020-05-29 12:15:36 -06001159 full_path).groups(1)[0]
C Shapiro5c877992020-04-29 12:11:28 -05001160 # Projects don't know about each other until they are integrated into the
1161 # build system. When this happens, the files need to be able to co-exist
1162 # without any collisions. This prefixes the project name (which is how
1163 # portage maps in the project), so project files co-exist and can be
1164 # installed together.
1165 # This is necessary to allow projects to share files at the program level
1166 # without having portage file installation collisions.
1167 build_root_dir = os.path.join(project_name, output_dir)
C Shapiro6830e6c2020-04-29 13:29:56 -05001168
David Burger1ba78a22020-06-18 18:42:47 -06001169 camera_map = _camera_map(configs, project_name)
David Burger52c9d322020-06-09 07:16:18 -06001170 dptf_map = _dptf_map(configs, project_name)
David Burgerceeb68a2020-09-03 11:31:10 -06001171 wifi_sar_map = _wifi_sar_map(configs, project_name, output_dir,
1172 build_root_dir)
David Burger52c9d322020-06-09 07:16:18 -06001173
C Shapiro2b6d5332020-05-06 17:51:35 -05001174 if os.path.exists(TOUCH_PATH):
Andrew Lambcd33f702020-06-11 10:45:16 -06001175 touch_fw = _build_touch_file_config(configs, project_name)
Andrew Lambcd33f702020-06-11 10:45:16 -06001176 arc_hw_feature_files = _write_arc_hardware_feature_files(
1177 configs, output_dir, build_root_dir)
C Shapiro5bf23a72020-04-24 11:40:17 -05001178 config_files = ConfigFiles(
C Shapiro5bf23a72020-04-24 11:40:17 -05001179 arc_hw_features=arc_hw_feature_files,
C Shapiro2b6d5332020-05-06 17:51:35 -05001180 touch_fw=touch_fw,
David Burger8ee9b4d2020-06-16 17:40:21 -06001181 dptf_map=dptf_map,
David Burgerceeb68a2020-09-03 11:31:10 -06001182 camera_map=camera_map,
1183 wifi_sar_map=wifi_sar_map)
Andrew Lambcd33f702020-06-11 10:45:16 -06001184 write_output(_transform_build_configs(configs, config_files), output)
David Burger7fd1dbe2020-03-26 09:26:55 -06001185
1186
1187def main(argv=None):
1188 """Main program which parses args and runs
1189
1190 Args:
1191 argv: List of command line arguments, if None uses sys.argv.
1192 """
1193 if argv is None:
1194 argv = sys.argv[1:]
Andrew Lambcd33f702020-06-11 10:45:16 -06001195 opts = parse_args(argv)
David Burger7fd1dbe2020-03-26 09:26:55 -06001196 Main(opts.project_configs, opts.program_config, opts.output)
1197
1198
1199if __name__ == '__main__':
1200 sys.exit(main(sys.argv[1:]))