blob: d3d02e9f555f7bc9081aba0ed23394deecf85448 [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}
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800106 config_id = _get_formatted_config_id(config.hw_design_config)
107 if config_id in config_files.arc_hw_features:
108 result['hardware-features'] = config_files.arc_hw_features[config_id]
Andrew Lambcd33f702020-06-11 10:45:16 -0600109 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
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800804def _get_formatted_config_id(design_config):
C Shapiro5bf23a72020-04-24 11:40:17 -0500805 return design_config.id.value.lower().replace(':', '_')
806
807
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800808def _write_file(output_dir, file_name, file_content):
David Burger77a1d312020-05-23 16:05:45 -0600809 os.makedirs(output_dir, exist_ok=True)
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800810 output = '{}/{}'.format(output_dir, file_name)
C Shapiroea33cff2020-05-11 13:32:05 -0500811 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
Ren-Pei Zeng9b5682d2020-10-14 17:37:30 +0800829 count = len(camera.devices)
830 has_front_camera = any(
831 (d.facing == camera_pb.FACING_FRONT for d in camera.devices))
832 has_back_camera = any(
833 (d.facing == camera_pb.FACING_BACK for d in camera.devices))
834 has_autofocus_back_camera = any((d.facing == camera_pb.FACING_BACK and
835 d.flags & camera_pb.FLAGS_SUPPORT_AUTOFOCUS
836 for d in camera.devices))
837 # Assumes MIPI cameras support FULL-level.
838 # TODO(kamesan): Setting this in project configs when there's an exception.
839 has_level_full_camera = any(
840 (d.interface == camera_pb.INTERFACE_MIPI for d in camera.devices))
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800841
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800842 return [
843 _feature('android.hardware.camera', has_back_camera),
844 _feature('android.hardware.camera.any', count > 0),
845 _feature('android.hardware.camera.autofocus', has_autofocus_back_camera),
846 _feature('android.hardware.camera.capability.manual_post_processing',
847 has_level_full_camera),
848 _feature('android.hardware.camera.capability.manual_sensor',
849 has_level_full_camera),
850 _feature('android.hardware.camera.front', has_front_camera),
851 _feature('android.hardware.camera.level.full', has_level_full_camera),
852 ]
853
854
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800855def _generate_arc_hardware_features(hw_features):
856 """Generates ARC hardware_features.xml file content.
C Shapiro5bf23a72020-04-24 11:40:17 -0500857
858 Args:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800859 hw_features: HardwareFeatures proto message.
C Shapiro5bf23a72020-04-24 11:40:17 -0500860 Returns:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800861 bytes of the hardware_features.xml content.
C Shapiro5bf23a72020-04-24 11:40:17 -0500862 """
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800863 touchscreen = _any_present([hw_features.screen.touch_support])
864 acc = hw_features.accelerometer
865 gyro = hw_features.gyroscope
866 compass = hw_features.magnetometer
867 light_sensor = hw_features.light_sensor
868 root = etree.Element('permissions')
869 root.extend(
870 _get_arc_camera_features(hw_features.camera) + [
871 _feature(
872 'android.hardware.sensor.accelerometer',
873 _any_present([acc.lid_accelerometer, acc.base_accelerometer])),
874 _feature('android.hardware.sensor.gyroscope',
875 _any_present([gyro.lid_gyroscope, gyro.base_gyroscope])),
876 _feature(
877 'android.hardware.sensor.compass',
878 _any_present(
879 [compass.lid_magnetometer, compass.base_magnetometer])),
880 _feature(
881 'android.hardware.sensor.light',
882 _any_present([
883 light_sensor.lid_lightsensor, light_sensor.base_lightsensor
884 ])),
885 _feature('android.hardware.touchscreen', touchscreen),
886 _feature('android.hardware.touchscreen.multitouch', touchscreen),
887 _feature('android.hardware.touchscreen.multitouch.distinct',
888 touchscreen),
889 _feature('android.hardware.touchscreen.multitouch.jazzhand',
890 touchscreen),
891 ])
892 return minidom.parseString(etree.tostring(root)).toprettyxml(
893 indent=' ', encoding='utf-8')
894
895
896def _write_files_by_design_config(configs, output_dir, build_dir, system_dir,
897 file_name_template, generate_file_content):
898 """Writes generated files for each design config.
899
900 Args:
901 configs: Source ConfigBundle to process.
902 output_dir: Path to the generated output.
903 build_dir: Path to the config file from portage's perspective.
904 system_dir: Path to the config file in the target device.
905 file_name_template: Template string of the config file name including one
906 format()-style replacement field for the config id, e.g. 'config_{}.xml'.
907 generate_file_content: Function to generate config file content from
908 HardwareFeatures proto.
909 Returns:
910 dict that maps the formatted config id to the correct file.
911 """
912 # pylint: disable=too-many-arguments,too-many-locals
C Shapiro5bf23a72020-04-24 11:40:17 -0500913 result = {}
C Shapiroea33cff2020-05-11 13:32:05 -0500914 configs_by_design = {}
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800915 for hw_design in configs.design_list:
C Shapiro5bf23a72020-04-24 11:40:17 -0500916 for design_config in hw_design.configs:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800917 config_content = generate_file_content(design_config.hardware_features)
C Shapiroea33cff2020-05-11 13:32:05 -0500918 design_name = hw_design.name.lower()
C Shapiro5bf23a72020-04-24 11:40:17 -0500919
C Shapiroea33cff2020-05-11 13:32:05 -0500920 # Constructs the following map:
921 # design_name -> config -> design_configs
922 # This allows any of the following file naming schemes:
923 # - All configs within a design share config (design_name prefix only)
924 # - Nobody shares (full design_name and config id prefix needed)
925 #
926 # Having shared configs when possible makes code reviews easier around
927 # the configs and makes debugging easier on the platform side.
C Shapiroea33cff2020-05-11 13:32:05 -0500928 arc_configs = configs_by_design.get(design_name, {})
929 design_configs = arc_configs.get(config_content, [])
930 design_configs.append(design_config)
931 arc_configs[config_content] = design_configs
932 configs_by_design[design_name] = arc_configs
C Shapiro9a3ac8c2020-04-25 07:49:21 -0500933
C Shapiroea33cff2020-05-11 13:32:05 -0500934 for design_name, unique_configs in configs_by_design.items():
935 for file_content, design_configs in unique_configs.items():
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800936 file_name = file_name_template.format(design_name)
Andrew Lamb2413c982020-05-29 12:15:36 -0600937 if len(unique_configs) == 1:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800938 _write_file(output_dir, file_name, file_content)
C Shapiro9a3ac8c2020-04-25 07:49:21 -0500939
Andrew Lamb2413c982020-05-29 12:15:36 -0600940 for design_config in design_configs:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800941 config_id = _get_formatted_config_id(design_config)
Andrew Lamb2413c982020-05-29 12:15:36 -0600942 if len(unique_configs) > 1:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800943 file_name = file_name_template.format(config_id)
944 _write_file(output_dir, file_name, file_content)
945 result[config_id] = _file_v2('{}/{}'.format(build_dir, file_name),
946 '{}/{}'.format(system_dir, file_name))
C Shapiro5bf23a72020-04-24 11:40:17 -0500947 return result
948
949
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800950def _write_arc_hardware_feature_files(configs, output_root_dir, build_root_dir):
951 return _write_files_by_design_config(configs, output_root_dir + '/arc',
952 build_root_dir + '/arc', '/etc',
953 'hardware_features_{}.xml',
954 _generate_arc_hardware_features)
955
956
Andrew Lambcd33f702020-06-11 10:45:16 -0600957def _read_config(path):
David Burgerd4f32962020-05-02 12:07:40 -0600958 """Reads a ConfigBundle proto from a json pb file.
David Burgere6f76222020-04-27 11:08:01 -0600959
960 Args:
David Burgerd4f32962020-05-02 12:07:40 -0600961 path: Path to the file encoding the json pb proto.
David Burgere6f76222020-04-27 11:08:01 -0600962 """
963 config = config_bundle_pb2.ConfigBundle()
964 with open(path, 'r') as f:
965 return json_format.Parse(f.read(), config)
966
967
Andrew Lambcd33f702020-06-11 10:45:16 -0600968def _merge_configs(configs):
David Burger7fd1dbe2020-03-26 09:26:55 -0600969 result = config_bundle_pb2.ConfigBundle()
970 for config in configs:
971 result.MergeFrom(config)
972
973 return result
974
975
David Burger1ba78a22020-06-18 18:42:47 -0600976def _camera_map(configs, project_name):
David Burger8ee9b4d2020-06-16 17:40:21 -0600977 """Produces a camera config map for the given configs.
978
979 Produces a map that maps from the design name to the camera config for that
980 design.
981
982 Args:
983 configs: Source ConfigBundle to process.
David Burger1ba78a22020-06-18 18:42:47 -0600984 project_name: Name of project processing for.
David Burger8ee9b4d2020-06-16 17:40:21 -0600985
986 Returns:
987 map from design name to camera config.
988 """
989 result = {}
Sean McAllisterf66887b2020-08-03 14:00:51 -0600990 for design in configs.design_list:
David Burger8ee9b4d2020-06-16 17:40:21 -0600991 design_name = design.name
David Burger0d9e8462020-06-19 14:12:37 -0600992 config_path = CAMERA_CONFIG_SOURCE_PATH_TEMPLATE.format(design_name.lower())
David Burger8ee9b4d2020-06-16 17:40:21 -0600993 if os.path.exists(config_path):
David Burger0d9e8462020-06-19 14:12:37 -0600994 destination = CAMERA_CONFIG_DEST_PATH_TEMPLATE.format(design_name.lower())
David Burger8ee9b4d2020-06-16 17:40:21 -0600995 result[design_name] = {
David Burger1ba78a22020-06-18 18:42:47 -0600996 'config-file':
997 _file_v2(os.path.join(project_name, config_path), destination),
David Burger8ee9b4d2020-06-16 17:40:21 -0600998 }
999 return result
1000
1001
David Burger52c9d322020-06-09 07:16:18 -06001002def _dptf_map(configs, project_name):
1003 """Produces a dptf map for the given configs.
1004
1005 Produces a map that maps from design name to the dptf file config for that
1006 design. It looks for the dptf files at:
David Burger2f0d9522020-07-30 10:52:28 -06001007 DPTF_PATH + '/' + DPTF_FILE
David Burger52c9d322020-06-09 07:16:18 -06001008 for a project wide config, that it maps under the empty string, and at:
David Burger2f0d9522020-07-30 10:52:28 -06001009 DPTF_PATH + '/' + design_name + '/' + DPTF_FILE
David Burger52c9d322020-06-09 07:16:18 -06001010 for design specific configs that it maps under the design name.
1011
1012 Args:
1013 configs: Source ConfigBundle to process.
1014 project_name: Name of project processing for.
1015
1016 Returns:
David Burger8ee9b4d2020-06-16 17:40:21 -06001017 map from design name or empty string (project wide), to dptf config.
David Burger52c9d322020-06-09 07:16:18 -06001018 """
1019 result = {}
David Burger52c9d322020-06-09 07:16:18 -06001020 # Looking at top level for project wide, and then for each design name
1021 # for design specific.
Sean McAllisterf66887b2020-08-03 14:00:51 -06001022 dirs = [""] + [d.name for d in configs.design_list]
David Burger52c9d322020-06-09 07:16:18 -06001023 for directory in dirs:
David Burgera2252762020-07-09 15:09:49 -06001024 design = directory.lower()
1025 if os.path.exists(os.path.join(DPTF_PATH, design, DPTF_FILE)):
David Burger2f0d9522020-07-30 10:52:28 -06001026 project_dptf_path = os.path.join(project_name, design, DPTF_FILE)
David Burger52c9d322020-06-09 07:16:18 -06001027 dptf_file = {
1028 'dptf-dv':
1029 project_dptf_path,
1030 'files': [
1031 _file(
David Burgera2252762020-07-09 15:09:49 -06001032 os.path.join(project_name, DPTF_PATH, design, DPTF_FILE),
David Burger52c9d322020-06-09 07:16:18 -06001033 os.path.join('/etc/dptf', project_dptf_path))
1034 ]
1035 }
1036 result[directory] = dptf_file
1037 return result
1038
1039
David Burgerceeb68a2020-09-03 11:31:10 -06001040def _wifi_sar_map(configs, project_name, output_dir, build_root_dir):
1041 """Constructs a map from design name to wifi sar config for that design.
1042
1043 Constructs a map from design name to the wifi sar config for that design.
1044 In the process a wifi sar hex file is generated that the config points at.
1045 This mapping is only made for the intel wifi where the generated file is
1046 provided when building coreboot.
1047
1048 Args:
1049 configs: Source ConfigBundle to process.
1050 project_name: Name of project processing for.
1051 output_dir: Path to the generated output.
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001052 build_root_dir: Path to the config file from portage's perspective.
David Burgerceeb68a2020-09-03 11:31:10 -06001053
1054 Returns:
1055 dict that maps the design name onto the wifi config for that design.
1056 """
1057 # pylint: disable=too-many-locals
1058 result = {}
1059 programs = {p.id.value: p for p in configs.program_list}
1060 sw_configs = list(configs.software_configs)
1061 for hw_design in configs.design_list:
1062 for hw_design_config in hw_design.configs:
1063 sw_config = _sw_config(sw_configs, hw_design_config.id.value)
1064 if sw_config.wifi_config.HasField('intel_config'):
1065 sar_file_content = _create_intel_sar_file_content(
1066 sw_config.wifi_config.intel_config)
1067 design_name = hw_design.name.lower()
1068 program = _lookup(hw_design.program_id, programs)
1069 wifi_sar_id = _extract_fw_config_value(hw_design_config, program,
1070 'Intel wifi sar id')
1071 output_path = os.path.join(output_dir, 'wifi')
1072 os.makedirs(output_path, exist_ok=True)
1073 filename = 'wifi_sar_{}.hex'.format(wifi_sar_id)
1074 output_path = os.path.join(output_path, filename)
1075 build_path = os.path.join(build_root_dir, 'wifi', filename)
1076 if os.path.exists(output_path):
1077 with open(output_path, 'r') as f:
1078 if f.read() != sar_file_content:
1079 raise Exception(
1080 'Project {} has conflicting wifi sar file content under '
1081 'wifi sar id {}.'.format(project_name, wifi_sar_id))
1082 else:
1083 with open(output_path, 'w') as f:
1084 f.write(sar_file_content)
1085 system_path = '/firmware/cbfs-rw-raw/{}/{}'.format(
1086 project_name, filename)
David Burger89e7cae2020-09-15 17:04:12 -06001087 result[design_name] = {'sar-file': _file_v2(build_path, system_path)}
David Burgerceeb68a2020-09-03 11:31:10 -06001088 return result
1089
1090
1091def _extract_fw_config_value(hw_design_config, program, name):
1092 """Extracts the firwmare config value with the given name.
1093
1094 Args:
1095 hw_design_config: Design extracting value from.
1096 program: Program the `hw_design_config` belongs to.
1097 name: Name of firmware config segment to extract.
1098
1099 Returns: the extracted value or raises a ValueError if no firmware
1100 configuration segment with `name` is found.
1101 """
1102 fw_config = hw_design_config.hardware_features.fw_config.value
1103 for fcs in program.firmware_configuration_segments:
1104 if fcs.name == name:
1105 value = fw_config & fcs.mask
1106 lsb_bit_set = (~fcs.mask + 1) & fcs.mask
1107 return value // lsb_bit_set
1108 raise ValueError(
1109 'No firmware configuration segment with name {} found'.format(name))
1110
1111
1112def _create_intel_sar_file_content(intel_config):
1113 """Creates and returns the intel sar file content for the given config.
1114
1115 Creates and returns the sar file content that is used with intel drivers
1116 only.
1117
1118 Args:
1119 intel_config: IntelConfig config.
1120
1121 Returns:
1122 sar file content for the given config, see:
1123 https://chromeos.google.com/partner/dlm/docs/connectivity/wifidyntxpower.html
1124 """
1125
1126 def to_hex(val):
1127 if val > 255 or val < 0:
1128 raise Exception('Sar file value %s out of range' % val)
1129 return '{0:0{1}X}'.format(val, 2)
1130
1131 def power_table(tpc):
1132 return (to_hex(tpc.limit_2g) + to_hex(tpc.limit_5g_1) +
1133 to_hex(tpc.limit_5g_2) + to_hex(tpc.limit_5g_3) +
1134 to_hex(tpc.limit_5g_4))
1135
1136 def wgds_value(wgds):
1137 return to_hex(wgds)
1138
1139 def offset_table(offsets):
1140 return (to_hex(offsets.max_2g) + to_hex(offsets.offset_2g_a) +
1141 to_hex(offsets.offset_2g_b) + to_hex(offsets.max_5g) +
1142 to_hex(offsets.offset_5g_a) + to_hex(offsets.offset_5g_b))
1143
1144 # See https://chromeos.google.com/partner/dlm/docs/connectivity/wifidyntxpower.html
1145 return (power_table(intel_config.tablet_mode_power_table_a) +
1146 power_table(intel_config.tablet_mode_power_table_b) +
1147 power_table(intel_config.non_tablet_mode_power_table_a) +
1148 power_table(intel_config.non_tablet_mode_power_table_b) +
1149 '00000000000000000000' + '00000000000000000000' +
1150 wgds_value(intel_config.wgds_version) +
1151 offset_table(intel_config.offset_fcc) +
1152 offset_table(intel_config.offset_eu) +
1153 offset_table(intel_config.offset_other))
1154
1155
Andrew Lambcd33f702020-06-11 10:45:16 -06001156def Main(project_configs, program_config, output): # pylint: disable=invalid-name
David Burger7fd1dbe2020-03-26 09:26:55 -06001157 """Transforms source proto config into platform JSON.
1158
1159 Args:
1160 project_configs: List of source project configs to transform.
1161 program_config: Program config for the given set of projects.
1162 output: Output file that will be generated by the transform.
1163 """
Andrew Lambcd33f702020-06-11 10:45:16 -06001164 configs = _merge_configs([_read_config(program_config)] +
1165 [_read_config(config) for config in project_configs])
C Shapiro2b6d5332020-05-06 17:51:35 -05001166 touch_fw = {}
David Burger8ee9b4d2020-06-16 17:40:21 -06001167 camera_map = {}
David Burgerceeb68a2020-09-03 11:31:10 -06001168 dptf_map = {}
1169 wifi_sar_map = {}
C Shapiro5bf23a72020-04-24 11:40:17 -05001170 output_dir = os.path.dirname(output)
C Shapiro5c877992020-04-29 12:11:28 -05001171 build_root_dir = output_dir
C Shapiro5c877992020-04-29 12:11:28 -05001172 if 'sw_build_config' in output_dir:
1173 full_path = os.path.realpath(output)
Andrew Lamb6b607732020-08-24 15:52:46 -06001174 project_name = re.match(r'.*/(\w*)/(public_)?sw_build_config/.*',
Andrew Lamb2413c982020-05-29 12:15:36 -06001175 full_path).groups(1)[0]
C Shapiro5c877992020-04-29 12:11:28 -05001176 # Projects don't know about each other until they are integrated into the
1177 # build system. When this happens, the files need to be able to co-exist
1178 # without any collisions. This prefixes the project name (which is how
1179 # portage maps in the project), so project files co-exist and can be
1180 # installed together.
1181 # This is necessary to allow projects to share files at the program level
1182 # without having portage file installation collisions.
1183 build_root_dir = os.path.join(project_name, output_dir)
C Shapiro6830e6c2020-04-29 13:29:56 -05001184
David Burger1ba78a22020-06-18 18:42:47 -06001185 camera_map = _camera_map(configs, project_name)
David Burger52c9d322020-06-09 07:16:18 -06001186 dptf_map = _dptf_map(configs, project_name)
David Burgerceeb68a2020-09-03 11:31:10 -06001187 wifi_sar_map = _wifi_sar_map(configs, project_name, output_dir,
1188 build_root_dir)
David Burger52c9d322020-06-09 07:16:18 -06001189
C Shapiro2b6d5332020-05-06 17:51:35 -05001190 if os.path.exists(TOUCH_PATH):
Andrew Lambcd33f702020-06-11 10:45:16 -06001191 touch_fw = _build_touch_file_config(configs, project_name)
Andrew Lambcd33f702020-06-11 10:45:16 -06001192 arc_hw_feature_files = _write_arc_hardware_feature_files(
1193 configs, output_dir, build_root_dir)
C Shapiro5bf23a72020-04-24 11:40:17 -05001194 config_files = ConfigFiles(
C Shapiro5bf23a72020-04-24 11:40:17 -05001195 arc_hw_features=arc_hw_feature_files,
C Shapiro2b6d5332020-05-06 17:51:35 -05001196 touch_fw=touch_fw,
David Burger8ee9b4d2020-06-16 17:40:21 -06001197 dptf_map=dptf_map,
David Burgerceeb68a2020-09-03 11:31:10 -06001198 camera_map=camera_map,
1199 wifi_sar_map=wifi_sar_map)
Andrew Lambcd33f702020-06-11 10:45:16 -06001200 write_output(_transform_build_configs(configs, config_files), output)
David Burger7fd1dbe2020-03-26 09:26:55 -06001201
1202
1203def main(argv=None):
1204 """Main program which parses args and runs
1205
1206 Args:
1207 argv: List of command line arguments, if None uses sys.argv.
1208 """
1209 if argv is None:
1210 argv = sys.argv[1:]
Andrew Lambcd33f702020-06-11 10:45:16 -06001211 opts = parse_args(argv)
David Burger7fd1dbe2020-03-26 09:26:55 -06001212 Main(opts.project_configs, opts.program_config, opts.output)
1213
1214
1215if __name__ == '__main__':
1216 sys.exit(main(sys.argv[1:]))