blob: b329738c98f7e1138e4831160a04b7f694e55018 [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
Andrew Lamb72d41362020-06-17 09:19:02 -0600154 flags['arc-build-properties'] = json_format.MessageToDict(
155 config.build_target.arc)
156
Andrew Lamb90b168c2020-06-22 10:42:30 -0600157 power_button = hw_features.power_button
158 if power_button.edge:
159 flags['ash-power-button-position'] = json.dumps({
160 'edge':
161 topology_pb2.HardwareFeatures.Button.Edge.Name(power_button.edge
162 ).lower(),
163 # Starlark sometimes represents float literals strangely, e.g. changing
164 # 0.9 to 0.899999. Round to two digits here.
165 'position':
166 round(power_button.position, 2)
167 })
168
169 volume_button = hw_features.volume_button
170 if volume_button.edge:
171 flags['ash-side-volume-button-position'] = json.dumps({
172 'region':
173 topology_pb2.HardwareFeatures.Button.Region.Name(
174 volume_button.region).lower(),
175 'edge':
176 topology_pb2.HardwareFeatures.Button.Edge.Name(volume_button.edge
177 ).lower(),
178 })
179
Andrew Lamb2e641e22020-06-15 12:30:41 -0600180 return sorted([f'--{k}={v}' if v else f'--{k}' for k, v in flags.items()])
Andrew Lamb319cc922020-06-15 10:45:46 -0600181
182
183def _build_ui(config: Config) -> dict:
184 """Builds the 'ui' property from cros_config_schema."""
185 return {'extra-ash-flags': _build_ash_flags(config)}
186
187
David Burger07af5242020-08-11 11:08:25 -0600188def _build_bluetooth(config):
C Shapiro90fda252020-04-17 14:34:57 -0500189 bt_flags = config.sw_config.bluetooth_config.flags
190 # Convert to native map (from proto wrapper)
191 bt_flags_map = dict(bt_flags)
192 result = {}
193 if bt_flags_map:
194 result['flags'] = bt_flags_map
C Shapiro90fda252020-04-17 14:34:57 -0500195 return result
196
David Burger7fd1dbe2020-03-26 09:26:55 -0600197
David Burgerceeb68a2020-09-03 11:31:10 -0600198def _build_ath10k_config(ath10k_config):
199 """Builds the wifi configuration for the ath10k driver.
200
201 Args:
202 ath10k_config: Ath10kConfig config.
203
204 Returns:
205 wifi configuration for the ath10k driver.
206 """
David Burgerec753912020-08-10 12:59:11 -0600207 result = {}
David Burgerec753912020-08-10 12:59:11 -0600208
David Burgerceeb68a2020-09-03 11:31:10 -0600209 def power_chain(power):
210 return {
211 'limit-2g': power.limit_2g,
212 'limit-5g': power.limit_5g,
213 }
David Burgerec753912020-08-10 12:59:11 -0600214
David Burgerceeb68a2020-09-03 11:31:10 -0600215 result['tablet-mode-power-table-ath10k'] = power_chain(
216 ath10k_config.tablet_mode_power_table)
217 result['non-tablet-mode-power-table-ath10k'] = power_chain(
218 ath10k_config.non_tablet_mode_power_table)
David Burgerec753912020-08-10 12:59:11 -0600219 return result
220
221
David Burgerceeb68a2020-09-03 11:31:10 -0600222def _build_rtw88_config(rtw88_config):
223 """Builds the wifi configuration for the rtw88 driver.
224
225 Args:
226 rtw88_config: Rtw88Config config.
227
228 Returns:
229 wifi configuration for the rtw88 driver.
230 """
231 result = {}
232
233 def power_chain(power):
234 return {
235 'limit-2g': power.limit_2g,
236 'limit-5g-1': power.limit_5g_1,
237 'limit-5g-3': power.limit_5g_3,
238 'limit-5g-4': power.limit_5g_4,
239 }
240
241 result['tablet-mode-power-table-rtw'] = power_chain(
242 rtw88_config.tablet_mode_power_table)
243 result['non-tablet-mode-power-table-rtw'] = power_chain(
244 rtw88_config.non_tablet_mode_power_table)
245
246 def offsets(offset):
247 return {
248 'offset-2g': offset.offset_2g,
249 'offset-5g': offset.offset_5g,
250 }
251
252 result['geo-offsets-fcc'] = offsets(rtw88_config.offset_fcc)
253 result['geo-offsets-eu'] = offsets(rtw88_config.offset_eu)
254 result['geo-offsets-rest-of-world'] = offsets(rtw88_config.offset_other)
255 return result
256
257
258def _build_intel_config(config, config_files):
259 """Builds the wifi configuration for the intel driver.
260
261 Args:
262 config: Config namedtuple
263 config_files: Map to look up the generated config files.
264
265 Returns:
266 wifi configuration for the intel driver.
267 """
268 design_name = config.hw_design.name.lower()
269 return config_files.wifi_sar_map.get(design_name)
270
271
272def _build_wifi(config, config_files):
273 """Builds the wifi configuration.
274
275 Args:
276 config: Config namedtuple
277 config_files: Map to look up the generated config files.
278
279 Returns:
280 wifi configuration.
281 """
282 config_field = config.sw_config.wifi_config.WhichOneof('wifi_config')
283 if config_field == 'ath10k_config':
284 return _build_ath10k_config(config.sw_config.wifi_config.ath10k_config)
285 if config_field == 'rtw88_config':
286 return _build_rtw88_config(config.sw_config.wifi_config.rtw88_config)
287 if config_field == 'intel_config':
288 return _build_intel_config(config, config_files)
289 return {}
290
291
Andrew Lambcd33f702020-06-11 10:45:16 -0600292def _build_fingerprint(hw_topology):
293 if not hw_topology.HasField('fingerprint'):
294 return None
295
296 fp = hw_topology.fingerprint.hardware_feature.fingerprint
297 result = {}
298 if fp.location != topology_pb2.HardwareFeatures.Fingerprint.NOT_PRESENT:
299 location = fp.Location.DESCRIPTOR.values_by_number[fp.location].name
300 result['sensor-location'] = location.lower().replace('_', '-')
301 if fp.board:
302 result['board'] = fp.board
Tom Hughesdfc35402020-06-29 16:02:09 -0700303 if fp.ro_version:
304 result['ro-version'] = fp.ro_version
305
Andrew Lambcd33f702020-06-11 10:45:16 -0600306 return result
David Burger7fd1dbe2020-03-26 09:26:55 -0600307
308
Trent Beginf067ccb2020-08-12 12:33:53 -0600309def _build_hardware_properties(hw_topology):
310 if not hw_topology.HasField('form_factor'):
311 return None
312
313 form_factor = hw_topology.form_factor.hardware_feature.form_factor.form_factor
314 result = {}
315 if form_factor in [
316 topology_pb2.HardwareFeatures.FormFactor.CHROMEBIT,
317 topology_pb2.HardwareFeatures.FormFactor.CHROMEBASE,
318 topology_pb2.HardwareFeatures.FormFactor.CHROMEBOX
319 ]:
320 result['psu-type'] = "AC_only"
321 else:
322 result['psu-type'] = "battery"
323
324 result['has-backlight'] = form_factor not in [
325 topology_pb2.HardwareFeatures.FormFactor.CHROMEBIT,
326 topology_pb2.HardwareFeatures.FormFactor.CHROMEBOX
327 ]
328
329 return result
330
331
Andrew Lambcd33f702020-06-11 10:45:16 -0600332def _fw_bcs_path(payload):
David Burger7fd1dbe2020-03-26 09:26:55 -0600333 if payload and payload.firmware_image_name:
Andrew Lamb2413c982020-05-29 12:15:36 -0600334 return 'bcs://%s.%d.%d.0.tbz2' % (payload.firmware_image_name,
335 payload.version.major,
336 payload.version.minor)
David Burger7fd1dbe2020-03-26 09:26:55 -0600337
Andrew Lambcd33f702020-06-11 10:45:16 -0600338 return None
David Burger7fd1dbe2020-03-26 09:26:55 -0600339
Andrew Lambcd33f702020-06-11 10:45:16 -0600340
341def _fw_build_target(payload):
David Burger7fd1dbe2020-03-26 09:26:55 -0600342 if payload:
343 return payload.build_target_name
344
Andrew Lambcd33f702020-06-11 10:45:16 -0600345 return None
David Burger7fd1dbe2020-03-26 09:26:55 -0600346
Andrew Lambcd33f702020-06-11 10:45:16 -0600347
348def _build_firmware(config):
David Burgerb70b6762020-05-21 12:14:59 -0600349 """Returns firmware config, or None if no build targets."""
Andrew Lamb3da156d2020-04-16 16:00:56 -0600350 fw_payload_config = config.sw_config.firmware
351 fw_build_config = config.sw_config.firmware_build_config
352 main_ro = fw_payload_config.main_ro_payload
353 main_rw = fw_payload_config.main_rw_payload
354 ec_ro = fw_payload_config.ec_ro_payload
355 pd_ro = fw_payload_config.pd_ro_payload
David Burger7fd1dbe2020-03-26 09:26:55 -0600356
357 build_targets = {}
Andrew Lamb3da156d2020-04-16 16:00:56 -0600358
David Burger8ee9b4d2020-06-16 17:40:21 -0600359 _upsert(fw_build_config.build_targets.depthcharge, build_targets,
360 'depthcharge')
361 _upsert(fw_build_config.build_targets.coreboot, build_targets, 'coreboot')
362 _upsert(fw_build_config.build_targets.ec, build_targets, 'ec')
363 _upsert(
Andrew Lambf8954ee2020-04-21 10:24:40 -0600364 list(fw_build_config.build_targets.ec_extras), build_targets, 'ec_extras')
David Burger8ee9b4d2020-06-16 17:40:21 -0600365 _upsert(fw_build_config.build_targets.libpayload, build_targets, 'libpayload')
David Burger7fd1dbe2020-03-26 09:26:55 -0600366
David Burgerb70b6762020-05-21 12:14:59 -0600367 if not build_targets:
368 return None
369
David Burger7fd1dbe2020-03-26 09:26:55 -0600370 result = {
371 'bcs-overlay': config.build_target.overlay_name,
372 'build-targets': build_targets,
David Burger7fd1dbe2020-03-26 09:26:55 -0600373 }
Andrew Lamb883fa042020-04-06 11:37:22 -0600374
David Burger8ee9b4d2020-06-16 17:40:21 -0600375 _upsert(main_ro.firmware_image_name.lower(), result, 'image-name')
Andrew Lamb883fa042020-04-06 11:37:22 -0600376
David Burger8ee9b4d2020-06-16 17:40:21 -0600377 _upsert(_fw_bcs_path(main_ro), result, 'main-ro-image')
378 _upsert(_fw_bcs_path(main_rw), result, 'main-rw-image')
379 _upsert(_fw_bcs_path(ec_ro), result, 'ec-ro-image')
380 _upsert(_fw_bcs_path(pd_ro), result, 'pd-ro-image')
David Burger7fd1dbe2020-03-26 09:26:55 -0600381
David Burger8ee9b4d2020-06-16 17:40:21 -0600382 _upsert(
Andrew Lambf39fbe82020-04-13 16:14:33 -0600383 config.hw_design_config.hardware_features.fw_config.value,
384 result,
385 'firmware-config',
386 )
387
David Burger7fd1dbe2020-03-26 09:26:55 -0600388 return result
389
390
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000391def _build_fw_signing(config, whitelabel):
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500392 if config.sw_config.firmware and config.device_signer_config:
David Burger68e0d142020-05-15 17:29:33 -0600393 hw_design = config.hw_design.name.lower()
Sam McNally2fc807f2020-07-16 18:13:53 +1000394 brand_scan_config = config.brand_config.scan_config
395 if brand_scan_config and brand_scan_config.whitelabel_tag:
396 signature_id = '%s-%s' % (hw_design, brand_scan_config.whitelabel_tag)
397 else:
398 signature_id = hw_design
399
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000400 result = {
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500401 'key-id': config.device_signer_config.key_id,
Sam McNally2fc807f2020-07-16 18:13:53 +1000402 'signature-id': signature_id,
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500403 }
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000404 if whitelabel:
405 result['sig-id-in-customization-id'] = True
406 return result
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500407 return {}
David Burger7fd1dbe2020-03-26 09:26:55 -0600408
409
Andrew Lambcd33f702020-06-11 10:45:16 -0600410def _file(source, destination):
Andrew Lamb2413c982020-05-29 12:15:36 -0600411 return {'destination': destination, 'source': source}
David Burger7fd1dbe2020-03-26 09:26:55 -0600412
413
David Burger40dfe3a2020-06-18 17:09:13 -0600414def _file_v2(build_path, system_path):
415 return {'build-path': build_path, 'system-path': system_path}
416
417
Andrew Lambcd33f702020-06-11 10:45:16 -0600418def _build_audio(config):
David Burger178f3ef2020-06-26 12:11:57 -0600419 if not config.sw_config.audio_configs:
420 return {}
David Burger7fd1dbe2020-03-26 09:26:55 -0600421 alsa_path = '/usr/share/alsa/ucm'
422 cras_path = '/etc/cras'
423 project_name = config.hw_design.name.lower()
David Burger43250662020-05-07 11:21:50 -0600424 program_name = config.program.name.lower()
David Burger7fd1dbe2020-03-26 09:26:55 -0600425 files = []
David Burger178f3ef2020-06-26 12:11:57 -0600426 ucm_suffix = None
427 for audio in config.sw_config.audio_configs:
428 card = audio.card_name
429 card_with_suffix = audio.card_name
430 if audio.ucm_suffix:
431 # TODO: last ucm_suffix wins.
432 ucm_suffix = audio.ucm_suffix
433 card_with_suffix += '.' + audio.ucm_suffix
434 if audio.ucm_file:
435 files.append(
436 _file(audio.ucm_file,
437 '%s/%s/HiFi.conf' % (alsa_path, card_with_suffix)))
438 if audio.ucm_master_file:
439 files.append(
440 _file(
441 audio.ucm_master_file, '%s/%s/%s.conf' %
Andrew Lamb2413c982020-05-29 12:15:36 -0600442 (alsa_path, card_with_suffix, card_with_suffix)))
David Burger178f3ef2020-06-26 12:11:57 -0600443 if audio.card_config_file:
444 files.append(
445 _file(audio.card_config_file,
446 '%s/%s/%s' % (cras_path, project_name, card)))
447 if audio.dsp_file:
448 files.append(
449 _file(audio.dsp_file, '%s/%s/dsp.ini' % (cras_path, project_name)))
450 if audio.module_file:
451 files.append(
452 _file(audio.module_file,
453 '/etc/modprobe.d/alsa-%s.conf' % program_name))
454 if audio.board_file:
455 files.append(
456 _file(audio.board_file,
457 '%s/%s/board.ini' % (cras_path, project_name)))
David Burger599ff7b2020-04-06 16:29:31 -0600458
459 result = {
David Burger7fd1dbe2020-03-26 09:26:55 -0600460 'main': {
461 'cras-config-dir': project_name,
462 'files': files,
463 }
464 }
David Burger178f3ef2020-06-26 12:11:57 -0600465
466 if ucm_suffix:
467 result['main']['ucm-suffix'] = ucm_suffix
David Burger599ff7b2020-04-06 16:29:31 -0600468
469 return result
David Burger7fd1dbe2020-03-26 09:26:55 -0600470
471
Andrew Lambcd33f702020-06-11 10:45:16 -0600472def _build_camera(hw_topology):
David Burger8aa8fa32020-04-14 08:30:34 -0600473 if hw_topology.HasField('camera'):
Ren-Pei Zengce869dd2020-08-18 01:29:37 +0800474 camera_pb = topology_pb2.HardwareFeatures.Camera
David Burger8aa8fa32020-04-14 08:30:34 -0600475 camera = hw_topology.camera.hardware_feature.camera
476 result = {}
477 if camera.count.value:
478 result['count'] = camera.count.value
Ren-Pei Zengce869dd2020-08-18 01:29:37 +0800479 if camera.devices:
480 result['devices'] = []
481 for device in camera.devices:
482 interface = {
483 camera_pb.INTERFACE_USB: 'usb',
484 camera_pb.INTERFACE_MIPI: 'mipi',
485 }[device.interface]
486 facing = {
487 camera_pb.FACING_FRONT: 'front',
488 camera_pb.FACING_BACK: 'back',
489 }[device.facing]
490 orientation = {
491 camera_pb.ORIENTATION_0: 0,
492 camera_pb.ORIENTATION_90: 90,
493 camera_pb.ORIENTATION_180: 180,
494 camera_pb.ORIENTATION_270: 270,
495 }[device.orientation]
Ren-Pei Zeng0bf96352020-09-28 18:44:42 +0800496 flags = {
497 'support-1080p':
498 bool(device.flags & camera_pb.FLAGS_SUPPORT_1080P),
499 'support-autofocus':
500 bool(device.flags & camera_pb.FLAGS_SUPPORT_AUTOFOCUS),
501 }
Ren-Pei Zengce869dd2020-08-18 01:29:37 +0800502 result['devices'].append({
Ren-Pei Zengce869dd2020-08-18 01:29:37 +0800503 'interface': interface,
504 'facing': facing,
505 'orientation': orientation,
Ren-Pei Zeng0bf96352020-09-28 18:44:42 +0800506 'flags': flags,
507 'ids': list(device.ids),
Ren-Pei Zengce869dd2020-08-18 01:29:37 +0800508 })
David Burger8aa8fa32020-04-14 08:30:34 -0600509 return result
510
Andrew Lambcd33f702020-06-11 10:45:16 -0600511 return None
David Burger8aa8fa32020-04-14 08:30:34 -0600512
Andrew Lambcd33f702020-06-11 10:45:16 -0600513
514def _build_identity(hw_scan_config, program, brand_scan_config=None):
David Burger7fd1dbe2020-03-26 09:26:55 -0600515 identity = {}
David Burger8ee9b4d2020-06-16 17:40:21 -0600516 _upsert(hw_scan_config.firmware_sku, identity, 'sku-id')
517 _upsert(hw_scan_config.smbios_name_match, identity, 'smbios-name-match')
Andrew Lamb7806ce92020-04-07 10:22:17 -0600518 # 'platform-name' is needed to support 'mosys platform name'. Clients should
519 # longer require platform name, but set it here for backwards compatibility.
David Burger8ee9b4d2020-06-16 17:40:21 -0600520 _upsert(program.name, identity, 'platform-name')
David Burger7fd1dbe2020-03-26 09:26:55 -0600521 # ARM architecture
David Burger8ee9b4d2020-06-16 17:40:21 -0600522 _upsert(hw_scan_config.device_tree_compatible_match, identity,
523 'device-tree-compatible-match')
David Burger7fd1dbe2020-03-26 09:26:55 -0600524
525 if brand_scan_config:
David Burger8ee9b4d2020-06-16 17:40:21 -0600526 _upsert(brand_scan_config.whitelabel_tag, identity, 'whitelabel-tag')
David Burger7fd1dbe2020-03-26 09:26:55 -0600527
528 return identity
529
530
Andrew Lambcd33f702020-06-11 10:45:16 -0600531def _lookup(id_value, id_map):
532 if not id_value.value:
533 return None
534
535 key = id_value.value
536 if key in id_map:
537 return id_map[id_value.value]
538 error = 'Failed to lookup %s with value: %s' % (
539 id_value.__class__.__name__.replace('Id', ''), key)
540 print(error)
541 print('Check the config contents provided:')
542 printer = pprint.PrettyPrinter(indent=4)
543 printer.pprint(id_map)
544 raise Exception(error)
David Burger7fd1dbe2020-03-26 09:26:55 -0600545
546
Andrew Lambcd33f702020-06-11 10:45:16 -0600547def _build_touch_file_config(config, project_name):
Sean McAllistereaf10b72020-08-03 13:41:06 -0600548 partners = {x.id.value: x for x in config.partner_list}
C Shapiro2b6d5332020-05-06 17:51:35 -0500549 files = []
550 for comp in config.components:
C Shapiro4813be62020-05-13 17:31:58 -0500551 touch = comp.touchscreen
552 # Everything is the same for Touch screen/pad, except different fields
553 if comp.HasField('touchpad'):
554 touch = comp.touchpad
555 if touch.product_id:
Andrew Lambcd33f702020-06-11 10:45:16 -0600556 vendor = _lookup(comp.manufacturer_id, partners)
C Shapiro2b6d5332020-05-06 17:51:35 -0500557 if not vendor:
Andrew Lamb2413c982020-05-29 12:15:36 -0600558 raise Exception("Manufacturer must be set for touch device %s" %
559 comp.id.value)
C Shapiro2b6d5332020-05-06 17:51:35 -0500560
C Shapiro4813be62020-05-13 17:31:58 -0500561 product_id = touch.product_id
562 fw_version = touch.fw_version
C Shapiro2b6d5332020-05-06 17:51:35 -0500563
C Shapiro2b6d5332020-05-06 17:51:35 -0500564 file_name = "%s_%s.bin" % (product_id, fw_version)
565 fw_file_path = os.path.join(TOUCH_PATH, vendor.name, file_name)
566
567 if not os.path.exists(fw_file_path):
Andrew Lamb2413c982020-05-29 12:15:36 -0600568 raise Exception("Touchscreen fw bin file doesn't exist at: %s" %
569 fw_file_path)
C Shapiro2b6d5332020-05-06 17:51:35 -0500570
C Shapiro303cece2020-07-22 07:15:21 -0500571 touch_vendor = vendor.touch_vendor
572 sym_link = touch_vendor.symlink_file_format.format(
573 vendor_name=vendor.name,
574 vendor_id=touch_vendor.vendor_id,
575 product_id=product_id,
576 fw_version=fw_version,
577 product_series=touch.product_series)
578
579 dest = "%s_%s" % (vendor.name, file_name)
580 if touch_vendor.destination_file_format:
581 dest = touch_vendor.destination_file_format.format(
582 vendor_name=vendor.name,
583 vendor_id=touch_vendor.vendor_id,
584 product_id=product_id,
585 fw_version=fw_version,
586 product_series=touch.product_series)
587
C Shapiro2b6d5332020-05-06 17:51:35 -0500588 files.append({
C Shapiro303cece2020-07-22 07:15:21 -0500589 "destination": os.path.join("/opt/google/touch/firmware", dest),
YH Lin9160fc52020-07-22 16:35:28 -0700590 "source": os.path.join(project_name, fw_file_path),
591 "symlink": os.path.join("/lib/firmware", sym_link),
C Shapiro2b6d5332020-05-06 17:51:35 -0500592 })
593
594 result = {}
David Burger8ee9b4d2020-06-16 17:40:21 -0600595 _upsert(files, result, 'files')
C Shapiro2b6d5332020-05-06 17:51:35 -0500596 return result
597
598
David Burgerceeb68a2020-09-03 11:31:10 -0600599def _sw_config(sw_configs, design_config_id):
600 """Returns the correct software config for `design_config_id`.
601
602 Returns the correct software config match for `design_config_id`. If no such
603 config or multiple such configs are found an exception is raised.
604 """
605 sw_config_matches = [
606 x for x in sw_configs if x.design_config_id.value == design_config_id
607 ]
608 if len(sw_config_matches) == 1:
609 return sw_config_matches[0]
610 if len(sw_config_matches) > 1:
611 raise ValueError('Multiple software configs found for: %s' %
612 design_config_id)
613 raise ValueError('Software config is required for: %s' % design_config_id)
614
615
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000616def _is_whitelabel(brand_configs, device_brands):
617 for device_brand in device_brands:
618 if device_brand.id.value in brand_configs:
619 brand_scan_config = brand_configs[device_brand.id.value].scan_config
620 if brand_scan_config and brand_scan_config.whitelabel_tag:
621 return True
622 return False
623
624
David Burgerceeb68a2020-09-03 11:31:10 -0600625def _transform_build_configs(config,
626 config_files=ConfigFiles({}, {}, {}, {}, {})):
Andrew Lambcd33f702020-06-11 10:45:16 -0600627 # pylint: disable=too-many-locals,too-many-branches
Sean McAllistereaf10b72020-08-03 13:41:06 -0600628 partners = {x.id.value: x for x in config.partner_list}
Sean McAllisterf38d1e92020-08-03 13:57:53 -0600629 programs = {x.id.value: x for x in config.program_list}
David Burger7fd1dbe2020-03-26 09:26:55 -0600630 sw_configs = list(config.software_configs)
Andrew Lambcd33f702020-06-11 10:45:16 -0600631 brand_configs = {x.brand_id.value: x for x in config.brand_configs}
David Burger7fd1dbe2020-03-26 09:26:55 -0600632
C Shapiroa0b766c2020-03-31 08:35:28 -0500633 if len(config.build_targets) != 1:
634 # Artifact of sharing the config_bundle for analysis and transforms.
635 # Integrated analysis of multiple programs/projects it the only time
636 # having multiple build targets would be valid.
637 raise Exception('Single build_target required for transform')
638
David Burger7fd1dbe2020-03-26 09:26:55 -0600639 results = {}
Sean McAllisterf66887b2020-08-03 14:00:51 -0600640 for hw_design in config.design_list:
Sean McAllister6cbb0ec2020-08-03 14:03:37 -0600641 if config.device_brand_list:
Andrew Lamb2413c982020-05-29 12:15:36 -0600642 device_brands = [
Sean McAllister6cbb0ec2020-08-03 14:03:37 -0600643 x for x in config.device_brand_list
Andrew Lamb2413c982020-05-29 12:15:36 -0600644 if x.design_id.value == hw_design.id.value
645 ]
David Burger7fd1dbe2020-03-26 09:26:55 -0600646 else:
647 device_brands = [device_brand_pb2.DeviceBrand()]
648
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000649 whitelabel = _is_whitelabel(brand_configs, device_brands)
650
David Burger7fd1dbe2020-03-26 09:26:55 -0600651 for device_brand in device_brands:
652 # Brand config can be empty since platform JSON config allows it
653 brand_config = brand_config_pb2.BrandConfig()
654 if device_brand.id.value in brand_configs:
655 brand_config = brand_configs[device_brand.id.value]
656
657 for hw_design_config in hw_design.configs:
David Burgerceeb68a2020-09-03 11:31:10 -0600658 sw_config = _sw_config(sw_configs, hw_design_config.id.value)
Andrew Lambcd33f702020-06-11 10:45:16 -0600659 program = _lookup(hw_design.program_id, programs)
C Shapiroadefd7c2020-05-19 16:37:21 -0500660 signer_configs_by_design = {}
661 signer_configs_by_brand = {}
662 for signer_config in program.device_signer_configs:
663 design_id = signer_config.design_id.value
664 brand_id = signer_config.brand_id.value
665 if design_id:
666 signer_configs_by_design[design_id] = signer_config
667 elif brand_id:
668 signer_configs_by_brand[brand_id] = signer_config
669 else:
670 raise Exception('No ID found for signer config: %s' % signer_config)
671
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500672 device_signer_config = None
C Shapiroadefd7c2020-05-19 16:37:21 -0500673 if signer_configs_by_design or signer_configs_by_brand:
674 design_id = hw_design.id.value
675 brand_id = device_brand.id.value
676 if design_id in signer_configs_by_design:
677 device_signer_config = signer_configs_by_design[design_id]
678 elif brand_id in signer_configs_by_brand:
679 device_signer_config = signer_configs_by_brand[brand_id]
680 else:
681 # Assume that if signer configs are set, every config is setup
Andrew Lamb2413c982020-05-29 12:15:36 -0600682 raise Exception('Signer config missing for design: %s, brand: %s' %
683 (design_id, brand_id))
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500684
Andrew Lambcd33f702020-06-11 10:45:16 -0600685 transformed_config = _transform_build_config(
C Shapiro90fda252020-04-17 14:34:57 -0500686 Config(
687 program=program,
688 hw_design=hw_design,
Andrew Lambcd33f702020-06-11 10:45:16 -0600689 odm=_lookup(hw_design.odm_id, partners),
C Shapiro90fda252020-04-17 14:34:57 -0500690 hw_design_config=hw_design_config,
691 device_brand=device_brand,
692 device_signer_config=device_signer_config,
Andrew Lambcd33f702020-06-11 10:45:16 -0600693 oem=_lookup(device_brand.oem_id, partners),
C Shapiro90fda252020-04-17 14:34:57 -0500694 sw_config=sw_config,
695 brand_config=brand_config,
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000696 build_target=config.build_targets[0]), config_files, whitelabel)
David Burger7fd1dbe2020-03-26 09:26:55 -0600697
Andrew Lamb2413c982020-05-29 12:15:36 -0600698 config_json = json.dumps(
699 transformed_config,
700 sort_keys=True,
701 indent=2,
702 separators=(',', ': '))
David Burger7fd1dbe2020-03-26 09:26:55 -0600703
704 if config_json not in results:
705 results[config_json] = transformed_config
706
707 return list(results.values())
708
709
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000710def _transform_build_config(config, config_files, whitelabel):
David Burger7fd1dbe2020-03-26 09:26:55 -0600711 """Transforms Config instance into target platform JSON schema.
712
713 Args:
714 config: Config namedtuple
C Shapiro5bf23a72020-04-24 11:40:17 -0500715 config_files: Map to look up the generated config files.
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000716 whitelabel: Whether the config is for a whitelabel design
David Burger7fd1dbe2020-03-26 09:26:55 -0600717
718 Returns:
719 Unique config payload based on the platform JSON schema.
720 """
721 result = {
Andrew Lamb2413c982020-05-29 12:15:36 -0600722 'identity':
Andrew Lambcd33f702020-06-11 10:45:16 -0600723 _build_identity(config.sw_config.id_scan_config, config.program,
724 config.brand_config.scan_config),
Andrew Lamb2413c982020-05-29 12:15:36 -0600725 'name':
726 config.hw_design.name.lower(),
David Burger7fd1dbe2020-03-26 09:26:55 -0600727 }
728
David Burger8ee9b4d2020-06-16 17:40:21 -0600729 _upsert(_build_arc(config, config_files), result, 'arc')
730 _upsert(_build_audio(config), result, 'audio')
David Burger07af5242020-08-11 11:08:25 -0600731 _upsert(_build_bluetooth(config), result, 'bluetooth')
David Burgerceeb68a2020-09-03 11:31:10 -0600732 _upsert(_build_wifi(config, config_files), result, 'wifi')
Andrew Lambca279902020-08-06 10:13:42 -0600733 _upsert(config.brand_config.wallpaper, result, 'wallpaper')
David Burger8ee9b4d2020-06-16 17:40:21 -0600734 _upsert(config.device_brand.brand_code, result, 'brand-code')
735 _upsert(
Andrew Lambcd33f702020-06-11 10:45:16 -0600736 _build_camera(config.hw_design_config.hardware_topology), result,
737 'camera')
David Burger8ee9b4d2020-06-16 17:40:21 -0600738 _upsert(_build_firmware(config), result, 'firmware')
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000739 _upsert(_build_fw_signing(config, whitelabel), result, 'firmware-signing')
David Burger8ee9b4d2020-06-16 17:40:21 -0600740 _upsert(
Andrew Lambcd33f702020-06-11 10:45:16 -0600741 _build_fingerprint(config.hw_design_config.hardware_topology), result,
Andrew Lamb2413c982020-05-29 12:15:36 -0600742 'fingerprint')
Andrew Lamb0d236ab2020-06-30 12:30:20 -0600743 _upsert(_build_ui(config), result, 'ui')
David Burger7fd1dbe2020-03-26 09:26:55 -0600744 power_prefs = config.sw_config.power_config.preferences
745 power_prefs_map = dict(
Andrew Lamb2413c982020-05-29 12:15:36 -0600746 (x.replace('_', '-'), power_prefs[x]) for x in power_prefs)
David Burger8ee9b4d2020-06-16 17:40:21 -0600747 _upsert(power_prefs_map, result, 'power')
748 if config_files.camera_map:
749 camera_file = config_files.camera_map.get(config.hw_design.name, {})
750 _upsert(camera_file, result, 'camera')
David Burger52c9d322020-06-09 07:16:18 -0600751 if config_files.dptf_map:
752 # Prefer design specific if found, if not fall back to project wide config
753 # mapped under the empty string.
754 if config_files.dptf_map.get(config.hw_design.name):
755 dptf_file = config_files.dptf_map[config.hw_design.name]
756 else:
757 dptf_file = config_files.dptf_map.get('')
David Burger8ee9b4d2020-06-16 17:40:21 -0600758 _upsert(dptf_file, result, 'thermal')
759 _upsert(config_files.touch_fw, result, 'touch')
Trent Beginf067ccb2020-08-12 12:33:53 -0600760 _upsert(
761 _build_hardware_properties(config.hw_design_config.hardware_topology),
762 result, 'hardware-properties')
David Burger7fd1dbe2020-03-26 09:26:55 -0600763
764 return result
765
766
Andrew Lambcd33f702020-06-11 10:45:16 -0600767def write_output(configs, output=None):
David Burger7fd1dbe2020-03-26 09:26:55 -0600768 """Writes a list of configs to platform JSON format.
769
770 Args:
771 configs: List of config dicts defined in cros_config_schema.yaml
772 output: Target file output (if None, prints to stdout)
773 """
Andrew Lamb2413c982020-05-29 12:15:36 -0600774 json_output = json.dumps({'chromeos': {
775 'configs': configs,
776 }},
777 sort_keys=True,
778 indent=2,
779 separators=(',', ': '))
David Burger7fd1dbe2020-03-26 09:26:55 -0600780 if output:
781 with open(output, 'w') as output_stream:
782 # Using print function adds proper trailing newline.
783 print(json_output, file=output_stream)
784 else:
785 print(json_output)
786
787
Andrew Lambcd33f702020-06-11 10:45:16 -0600788def _feature(name, present):
C Shapiro5bf23a72020-04-24 11:40:17 -0500789 attrib = {'name': name}
790 if present:
791 return etree.Element('feature', attrib=attrib)
Andrew Lambcd33f702020-06-11 10:45:16 -0600792
793 return etree.Element('unavailable-feature', attrib=attrib)
C Shapiro5bf23a72020-04-24 11:40:17 -0500794
795
Andrew Lambcd33f702020-06-11 10:45:16 -0600796def _any_present(features):
Andrew Lamb2413c982020-05-29 12:15:36 -0600797 return topology_pb2.HardwareFeatures.PRESENT in features
C Shapiro5bf23a72020-04-24 11:40:17 -0500798
799
Andrew Lambcd33f702020-06-11 10:45:16 -0600800def _arc_hardware_feature_id(design_config):
C Shapiro5bf23a72020-04-24 11:40:17 -0500801 return design_config.id.value.lower().replace(':', '_')
802
803
Andrew Lambcd33f702020-06-11 10:45:16 -0600804def _write_arc_hardware_feature_file(output_dir, file_name, config_content):
David Burger77a1d312020-05-23 16:05:45 -0600805 output_dir += '/arc'
806 os.makedirs(output_dir, exist_ok=True)
807 output = '%s/%s' % (output_dir, file_name)
Andrew Lamb2413c982020-05-29 12:15:36 -0600808 file_content = minidom.parseString(config_content).toprettyxml(
809 indent=' ', encoding='utf-8')
C Shapiroea33cff2020-05-11 13:32:05 -0500810
811 with open(output, 'wb') as f:
812 f.write(file_content)
813
814
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800815def _get_arc_camera_features(camera):
816 """Gets camera related features for ARC hardware_features.xml from camera
817 topology. Check
818 https://developer.android.com/reference/android/content/pm/PackageManager#FEATURE_CAMERA
819 and CTS android.app.cts.SystemFeaturesTest#testCameraFeatures for the correct
820 settings.
821
822 Args:
823 camera: A HardwareFeatures.Camera proto message.
824 Returns:
825 list of camera related ARC features as XML elements.
826 """
827 camera_pb = topology_pb2.HardwareFeatures.Camera
828
829 if len(camera.devices) > 0:
830 count = len(camera.devices)
831 has_front_camera = any(
832 (d.facing == camera_pb.FACING_FRONT for d in camera.devices))
833 has_back_camera = any(
834 (d.facing == camera_pb.FACING_BACK for d in camera.devices))
Ren-Pei Zeng0bf96352020-09-28 18:44:42 +0800835 has_autofocus_back_camera = any((d.facing == camera_pb.FACING_BACK and
836 d.flags & camera_pb.FLAGS_SUPPORT_AUTOFOCUS
837 for d in camera.devices))
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800838 # Assumes MIPI cameras support FULL-level.
839 # TODO(kamesan): Setting this in project configs when there's an exception.
840 has_level_full_camera = any(
841 (d.interface == camera_pb.INTERFACE_MIPI for d in camera.devices))
842 else:
843 # Fallback to use the old proto definition.
844 count = camera.count.value
845 has_front_camera = count > 0
846 has_back_camera = count > 1
Ren-Pei Zeng0bf96352020-09-28 18:44:42 +0800847 has_autofocus_back_camera = has_back_camera
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800848 has_level_full_camera = False
849
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800850 return [
851 _feature('android.hardware.camera', has_back_camera),
852 _feature('android.hardware.camera.any', count > 0),
853 _feature('android.hardware.camera.autofocus', has_autofocus_back_camera),
854 _feature('android.hardware.camera.capability.manual_post_processing',
855 has_level_full_camera),
856 _feature('android.hardware.camera.capability.manual_sensor',
857 has_level_full_camera),
858 _feature('android.hardware.camera.front', has_front_camera),
859 _feature('android.hardware.camera.level.full', has_level_full_camera),
860 ]
861
862
Andrew Lambcd33f702020-06-11 10:45:16 -0600863def _write_arc_hardware_feature_files(config, output_dir, build_root_dir):
C Shapiro5bf23a72020-04-24 11:40:17 -0500864 """Writes ARC hardware_feature.xml files for each config
865
866 Args:
867 config: Source ConfigBundle to process.
868 output_dir: Path to the generated output.
C Shapiro5c877992020-04-29 12:11:28 -0500869 build_root_path: Path to the config file from portage's perspective.
C Shapiro5bf23a72020-04-24 11:40:17 -0500870 Returns:
871 dict that maps the design_config_id onto the correct file.
872 """
Andrew Lambcd33f702020-06-11 10:45:16 -0600873 # pylint: disable=too-many-locals
C Shapiro5bf23a72020-04-24 11:40:17 -0500874 result = {}
C Shapiroea33cff2020-05-11 13:32:05 -0500875 configs_by_design = {}
Sean McAllisterf66887b2020-08-03 14:00:51 -0600876 for hw_design in config.design_list:
C Shapiro5bf23a72020-04-24 11:40:17 -0500877 for design_config in hw_design.configs:
878 hw_features = design_config.hardware_features
Andrew Lambcd33f702020-06-11 10:45:16 -0600879 touchscreen = _any_present([hw_features.screen.touch_support])
C Shapiro5bf23a72020-04-24 11:40:17 -0500880 acc = hw_features.accelerometer
881 gyro = hw_features.gyroscope
882 compass = hw_features.magnetometer
Andrew Lambcd33f702020-06-11 10:45:16 -0600883 light_sensor = hw_features.light_sensor
C Shapiro5bf23a72020-04-24 11:40:17 -0500884 root = etree.Element('permissions')
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800885 root.extend(
886 _get_arc_camera_features(hw_features.camera) + [
887 _feature(
888 'android.hardware.sensor.accelerometer',
889 _any_present([acc.lid_accelerometer, acc.base_accelerometer
890 ])),
891 _feature('android.hardware.sensor.gyroscope',
892 _any_present([gyro.lid_gyroscope, gyro.base_gyroscope])),
893 _feature(
894 'android.hardware.sensor.compass',
895 _any_present(
896 [compass.lid_magnetometer, compass.base_magnetometer])),
897 _feature(
898 'android.hardware.sensor.light',
899 _any_present([
900 light_sensor.lid_lightsensor,
901 light_sensor.base_lightsensor
902 ])),
903 _feature('android.hardware.touchscreen', touchscreen),
904 _feature('android.hardware.touchscreen.multitouch', touchscreen),
905 _feature('android.hardware.touchscreen.multitouch.distinct',
906 touchscreen),
907 _feature('android.hardware.touchscreen.multitouch.jazzhand',
908 touchscreen),
909 ])
C Shapiro5bf23a72020-04-24 11:40:17 -0500910
C Shapiroea33cff2020-05-11 13:32:05 -0500911 design_name = hw_design.name.lower()
C Shapiro5bf23a72020-04-24 11:40:17 -0500912
C Shapiroea33cff2020-05-11 13:32:05 -0500913 # Constructs the following map:
914 # design_name -> config -> design_configs
915 # This allows any of the following file naming schemes:
916 # - All configs within a design share config (design_name prefix only)
917 # - Nobody shares (full design_name and config id prefix needed)
918 #
919 # Having shared configs when possible makes code reviews easier around
920 # the configs and makes debugging easier on the platform side.
921 config_content = etree.tostring(root)
922 arc_configs = configs_by_design.get(design_name, {})
923 design_configs = arc_configs.get(config_content, [])
924 design_configs.append(design_config)
925 arc_configs[config_content] = design_configs
926 configs_by_design[design_name] = arc_configs
C Shapiro9a3ac8c2020-04-25 07:49:21 -0500927
C Shapiroea33cff2020-05-11 13:32:05 -0500928 for design_name, unique_configs in configs_by_design.items():
929 for file_content, design_configs in unique_configs.items():
Andrew Lamb2413c982020-05-29 12:15:36 -0600930 file_name = 'hardware_features_%s.xml' % design_name
931 if len(unique_configs) == 1:
Andrew Lambcd33f702020-06-11 10:45:16 -0600932 _write_arc_hardware_feature_file(output_dir, file_name, file_content)
C Shapiro9a3ac8c2020-04-25 07:49:21 -0500933
Andrew Lamb2413c982020-05-29 12:15:36 -0600934 for design_config in design_configs:
Andrew Lambcd33f702020-06-11 10:45:16 -0600935 feature_id = _arc_hardware_feature_id(design_config)
Andrew Lamb2413c982020-05-29 12:15:36 -0600936 if len(unique_configs) > 1:
937 file_name = 'hardware_features_%s.xml' % feature_id
Andrew Lambcd33f702020-06-11 10:45:16 -0600938 _write_arc_hardware_feature_file(output_dir, file_name, file_content)
David Burger40dfe3a2020-06-18 17:09:13 -0600939 result[feature_id] = _file_v2('%s/arc/%s' % (build_root_dir, file_name),
940 '/etc/%s' % file_name)
C Shapiro5bf23a72020-04-24 11:40:17 -0500941 return result
942
943
Andrew Lambcd33f702020-06-11 10:45:16 -0600944def _read_config(path):
David Burgerd4f32962020-05-02 12:07:40 -0600945 """Reads a ConfigBundle proto from a json pb file.
David Burgere6f76222020-04-27 11:08:01 -0600946
947 Args:
David Burgerd4f32962020-05-02 12:07:40 -0600948 path: Path to the file encoding the json pb proto.
David Burgere6f76222020-04-27 11:08:01 -0600949 """
950 config = config_bundle_pb2.ConfigBundle()
951 with open(path, 'r') as f:
952 return json_format.Parse(f.read(), config)
953
954
Andrew Lambcd33f702020-06-11 10:45:16 -0600955def _merge_configs(configs):
David Burger7fd1dbe2020-03-26 09:26:55 -0600956 result = config_bundle_pb2.ConfigBundle()
957 for config in configs:
958 result.MergeFrom(config)
959
960 return result
961
962
David Burger1ba78a22020-06-18 18:42:47 -0600963def _camera_map(configs, project_name):
David Burger8ee9b4d2020-06-16 17:40:21 -0600964 """Produces a camera config map for the given configs.
965
966 Produces a map that maps from the design name to the camera config for that
967 design.
968
969 Args:
970 configs: Source ConfigBundle to process.
David Burger1ba78a22020-06-18 18:42:47 -0600971 project_name: Name of project processing for.
David Burger8ee9b4d2020-06-16 17:40:21 -0600972
973 Returns:
974 map from design name to camera config.
975 """
976 result = {}
Sean McAllisterf66887b2020-08-03 14:00:51 -0600977 for design in configs.design_list:
David Burger8ee9b4d2020-06-16 17:40:21 -0600978 design_name = design.name
David Burger0d9e8462020-06-19 14:12:37 -0600979 config_path = CAMERA_CONFIG_SOURCE_PATH_TEMPLATE.format(design_name.lower())
David Burger8ee9b4d2020-06-16 17:40:21 -0600980 if os.path.exists(config_path):
David Burger0d9e8462020-06-19 14:12:37 -0600981 destination = CAMERA_CONFIG_DEST_PATH_TEMPLATE.format(design_name.lower())
David Burger8ee9b4d2020-06-16 17:40:21 -0600982 result[design_name] = {
David Burger1ba78a22020-06-18 18:42:47 -0600983 'config-file':
984 _file_v2(os.path.join(project_name, config_path), destination),
David Burger8ee9b4d2020-06-16 17:40:21 -0600985 }
986 return result
987
988
David Burger52c9d322020-06-09 07:16:18 -0600989def _dptf_map(configs, project_name):
990 """Produces a dptf map for the given configs.
991
992 Produces a map that maps from design name to the dptf file config for that
993 design. It looks for the dptf files at:
David Burger2f0d9522020-07-30 10:52:28 -0600994 DPTF_PATH + '/' + DPTF_FILE
David Burger52c9d322020-06-09 07:16:18 -0600995 for a project wide config, that it maps under the empty string, and at:
David Burger2f0d9522020-07-30 10:52:28 -0600996 DPTF_PATH + '/' + design_name + '/' + DPTF_FILE
David Burger52c9d322020-06-09 07:16:18 -0600997 for design specific configs that it maps under the design name.
998
999 Args:
1000 configs: Source ConfigBundle to process.
1001 project_name: Name of project processing for.
1002
1003 Returns:
David Burger8ee9b4d2020-06-16 17:40:21 -06001004 map from design name or empty string (project wide), to dptf config.
David Burger52c9d322020-06-09 07:16:18 -06001005 """
1006 result = {}
David Burger52c9d322020-06-09 07:16:18 -06001007 # Looking at top level for project wide, and then for each design name
1008 # for design specific.
Sean McAllisterf66887b2020-08-03 14:00:51 -06001009 dirs = [""] + [d.name for d in configs.design_list]
David Burger52c9d322020-06-09 07:16:18 -06001010 for directory in dirs:
David Burgera2252762020-07-09 15:09:49 -06001011 design = directory.lower()
1012 if os.path.exists(os.path.join(DPTF_PATH, design, DPTF_FILE)):
David Burger2f0d9522020-07-30 10:52:28 -06001013 project_dptf_path = os.path.join(project_name, design, DPTF_FILE)
David Burger52c9d322020-06-09 07:16:18 -06001014 dptf_file = {
1015 'dptf-dv':
1016 project_dptf_path,
1017 'files': [
1018 _file(
David Burgera2252762020-07-09 15:09:49 -06001019 os.path.join(project_name, DPTF_PATH, design, DPTF_FILE),
David Burger52c9d322020-06-09 07:16:18 -06001020 os.path.join('/etc/dptf', project_dptf_path))
1021 ]
1022 }
1023 result[directory] = dptf_file
1024 return result
1025
1026
David Burgerceeb68a2020-09-03 11:31:10 -06001027def _wifi_sar_map(configs, project_name, output_dir, build_root_dir):
1028 """Constructs a map from design name to wifi sar config for that design.
1029
1030 Constructs a map from design name to the wifi sar config for that design.
1031 In the process a wifi sar hex file is generated that the config points at.
1032 This mapping is only made for the intel wifi where the generated file is
1033 provided when building coreboot.
1034
1035 Args:
1036 configs: Source ConfigBundle to process.
1037 project_name: Name of project processing for.
1038 output_dir: Path to the generated output.
1039 build_root_path: Path to the config file from portage's perspective.
1040
1041 Returns:
1042 dict that maps the design name onto the wifi config for that design.
1043 """
1044 # pylint: disable=too-many-locals
1045 result = {}
1046 programs = {p.id.value: p for p in configs.program_list}
1047 sw_configs = list(configs.software_configs)
1048 for hw_design in configs.design_list:
1049 for hw_design_config in hw_design.configs:
1050 sw_config = _sw_config(sw_configs, hw_design_config.id.value)
1051 if sw_config.wifi_config.HasField('intel_config'):
1052 sar_file_content = _create_intel_sar_file_content(
1053 sw_config.wifi_config.intel_config)
1054 design_name = hw_design.name.lower()
1055 program = _lookup(hw_design.program_id, programs)
1056 wifi_sar_id = _extract_fw_config_value(hw_design_config, program,
1057 'Intel wifi sar id')
1058 output_path = os.path.join(output_dir, 'wifi')
1059 os.makedirs(output_path, exist_ok=True)
1060 filename = 'wifi_sar_{}.hex'.format(wifi_sar_id)
1061 output_path = os.path.join(output_path, filename)
1062 build_path = os.path.join(build_root_dir, 'wifi', filename)
1063 if os.path.exists(output_path):
1064 with open(output_path, 'r') as f:
1065 if f.read() != sar_file_content:
1066 raise Exception(
1067 'Project {} has conflicting wifi sar file content under '
1068 'wifi sar id {}.'.format(project_name, wifi_sar_id))
1069 else:
1070 with open(output_path, 'w') as f:
1071 f.write(sar_file_content)
1072 system_path = '/firmware/cbfs-rw-raw/{}/{}'.format(
1073 project_name, filename)
David Burger89e7cae2020-09-15 17:04:12 -06001074 result[design_name] = {'sar-file': _file_v2(build_path, system_path)}
David Burgerceeb68a2020-09-03 11:31:10 -06001075 return result
1076
1077
1078def _extract_fw_config_value(hw_design_config, program, name):
1079 """Extracts the firwmare config value with the given name.
1080
1081 Args:
1082 hw_design_config: Design extracting value from.
1083 program: Program the `hw_design_config` belongs to.
1084 name: Name of firmware config segment to extract.
1085
1086 Returns: the extracted value or raises a ValueError if no firmware
1087 configuration segment with `name` is found.
1088 """
1089 fw_config = hw_design_config.hardware_features.fw_config.value
1090 for fcs in program.firmware_configuration_segments:
1091 if fcs.name == name:
1092 value = fw_config & fcs.mask
1093 lsb_bit_set = (~fcs.mask + 1) & fcs.mask
1094 return value // lsb_bit_set
1095 raise ValueError(
1096 'No firmware configuration segment with name {} found'.format(name))
1097
1098
1099def _create_intel_sar_file_content(intel_config):
1100 """Creates and returns the intel sar file content for the given config.
1101
1102 Creates and returns the sar file content that is used with intel drivers
1103 only.
1104
1105 Args:
1106 intel_config: IntelConfig config.
1107
1108 Returns:
1109 sar file content for the given config, see:
1110 https://chromeos.google.com/partner/dlm/docs/connectivity/wifidyntxpower.html
1111 """
1112
1113 def to_hex(val):
1114 if val > 255 or val < 0:
1115 raise Exception('Sar file value %s out of range' % val)
1116 return '{0:0{1}X}'.format(val, 2)
1117
1118 def power_table(tpc):
1119 return (to_hex(tpc.limit_2g) + to_hex(tpc.limit_5g_1) +
1120 to_hex(tpc.limit_5g_2) + to_hex(tpc.limit_5g_3) +
1121 to_hex(tpc.limit_5g_4))
1122
1123 def wgds_value(wgds):
1124 return to_hex(wgds)
1125
1126 def offset_table(offsets):
1127 return (to_hex(offsets.max_2g) + to_hex(offsets.offset_2g_a) +
1128 to_hex(offsets.offset_2g_b) + to_hex(offsets.max_5g) +
1129 to_hex(offsets.offset_5g_a) + to_hex(offsets.offset_5g_b))
1130
1131 # See https://chromeos.google.com/partner/dlm/docs/connectivity/wifidyntxpower.html
1132 return (power_table(intel_config.tablet_mode_power_table_a) +
1133 power_table(intel_config.tablet_mode_power_table_b) +
1134 power_table(intel_config.non_tablet_mode_power_table_a) +
1135 power_table(intel_config.non_tablet_mode_power_table_b) +
1136 '00000000000000000000' + '00000000000000000000' +
1137 wgds_value(intel_config.wgds_version) +
1138 offset_table(intel_config.offset_fcc) +
1139 offset_table(intel_config.offset_eu) +
1140 offset_table(intel_config.offset_other))
1141
1142
Andrew Lambcd33f702020-06-11 10:45:16 -06001143def Main(project_configs, program_config, output): # pylint: disable=invalid-name
David Burger7fd1dbe2020-03-26 09:26:55 -06001144 """Transforms source proto config into platform JSON.
1145
1146 Args:
1147 project_configs: List of source project configs to transform.
1148 program_config: Program config for the given set of projects.
1149 output: Output file that will be generated by the transform.
1150 """
Andrew Lambcd33f702020-06-11 10:45:16 -06001151 configs = _merge_configs([_read_config(program_config)] +
1152 [_read_config(config) for config in project_configs])
C Shapiro5bf23a72020-04-24 11:40:17 -05001153 arc_hw_feature_files = {}
C Shapiro2b6d5332020-05-06 17:51:35 -05001154 touch_fw = {}
David Burger8ee9b4d2020-06-16 17:40:21 -06001155 camera_map = {}
David Burgerceeb68a2020-09-03 11:31:10 -06001156 dptf_map = {}
1157 wifi_sar_map = {}
C Shapiro5bf23a72020-04-24 11:40:17 -05001158 output_dir = os.path.dirname(output)
C Shapiro5c877992020-04-29 12:11:28 -05001159 build_root_dir = output_dir
C Shapiro5c877992020-04-29 12:11:28 -05001160 if 'sw_build_config' in output_dir:
1161 full_path = os.path.realpath(output)
Andrew Lamb6b607732020-08-24 15:52:46 -06001162 project_name = re.match(r'.*/(\w*)/(public_)?sw_build_config/.*',
Andrew Lamb2413c982020-05-29 12:15:36 -06001163 full_path).groups(1)[0]
C Shapiro5c877992020-04-29 12:11:28 -05001164 # Projects don't know about each other until they are integrated into the
1165 # build system. When this happens, the files need to be able to co-exist
1166 # without any collisions. This prefixes the project name (which is how
1167 # portage maps in the project), so project files co-exist and can be
1168 # installed together.
1169 # This is necessary to allow projects to share files at the program level
1170 # without having portage file installation collisions.
1171 build_root_dir = os.path.join(project_name, output_dir)
C Shapiro6830e6c2020-04-29 13:29:56 -05001172
David Burger1ba78a22020-06-18 18:42:47 -06001173 camera_map = _camera_map(configs, project_name)
David Burger52c9d322020-06-09 07:16:18 -06001174 dptf_map = _dptf_map(configs, project_name)
David Burgerceeb68a2020-09-03 11:31:10 -06001175 wifi_sar_map = _wifi_sar_map(configs, project_name, output_dir,
1176 build_root_dir)
David Burger52c9d322020-06-09 07:16:18 -06001177
C Shapiro2b6d5332020-05-06 17:51:35 -05001178 if os.path.exists(TOUCH_PATH):
Andrew Lambcd33f702020-06-11 10:45:16 -06001179 touch_fw = _build_touch_file_config(configs, project_name)
Andrew Lambcd33f702020-06-11 10:45:16 -06001180 arc_hw_feature_files = _write_arc_hardware_feature_files(
1181 configs, output_dir, build_root_dir)
C Shapiro5bf23a72020-04-24 11:40:17 -05001182 config_files = ConfigFiles(
C Shapiro5bf23a72020-04-24 11:40:17 -05001183 arc_hw_features=arc_hw_feature_files,
C Shapiro2b6d5332020-05-06 17:51:35 -05001184 touch_fw=touch_fw,
David Burger8ee9b4d2020-06-16 17:40:21 -06001185 dptf_map=dptf_map,
David Burgerceeb68a2020-09-03 11:31:10 -06001186 camera_map=camera_map,
1187 wifi_sar_map=wifi_sar_map)
Andrew Lambcd33f702020-06-11 10:45:16 -06001188 write_output(_transform_build_configs(configs, config_files), output)
David Burger7fd1dbe2020-03-26 09:26:55 -06001189
1190
1191def main(argv=None):
1192 """Main program which parses args and runs
1193
1194 Args:
1195 argv: List of command line arguments, if None uses sys.argv.
1196 """
1197 if argv is None:
1198 argv = sys.argv[1:]
Andrew Lambcd33f702020-06-11 10:45:16 -06001199 opts = parse_args(argv)
David Burger7fd1dbe2020-03-26 09:26:55 -06001200 Main(opts.project_configs, opts.program_config, opts.output)
1201
1202
1203if __name__ == '__main__':
1204 sys.exit(main(sys.argv[1:]))