blob: 211f65e2cb83cfc04e1d7f1759d99bd84b7f4192 [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
David Burger7fd1dbe2020-03-26 09:26:55 -060016
Andrew Lamb319cc922020-06-15 10:45:46 -060017from typing import List
18
David Burger7fd1dbe2020-03-26 09:26:55 -060019from collections import namedtuple
20
Andrew Lambcd33f702020-06-11 10:45:16 -060021from google.protobuf import json_format
Ren-Pei Zengacf03be2020-11-11 13:56:51 +080022from lxml import etree
Andrew Lambcd33f702020-06-11 10:45:16 -060023
Prathmesh Prabhu72f8a002020-04-10 09:57:53 -070024from chromiumos.config.api import device_brand_pb2
David Burger92609a32020-04-23 10:38:50 -060025from chromiumos.config.api import topology_pb2
C Shapiro5bf23a72020-04-24 11:40:17 -050026from chromiumos.config.payload import config_bundle_pb2
Prathmesh Prabhu72f8a002020-04-10 09:57:53 -070027from chromiumos.config.api.software import brand_config_pb2
David Burger7fd1dbe2020-03-26 09:26:55 -060028
Andrew Lamb2413c982020-05-29 12:15:36 -060029Config = namedtuple('Config', [
30 'program', 'hw_design', 'odm', 'hw_design_config', 'device_brand',
C Shapirod5545f12020-11-30 16:37:04 -060031 'device_signer_config', 'oem', 'sw_config', 'brand_config'
Andrew Lamb2413c982020-05-29 12:15:36 -060032])
David Burger7fd1dbe2020-03-26 09:26:55 -060033
Ren-Pei Zengacf03be2020-11-11 13:56:51 +080034ConfigFiles = namedtuple('ConfigFiles', [
35 'arc_hw_features', 'arc_media_profiles', 'touch_fw', 'dptf_map',
36 'camera_map', 'wifi_sar_map'
37])
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
Ren-Pei Zengacf03be2020-11-11 13:56:51 +080049XML_DECLARATION = b'<?xml version="1.0" encoding="utf-8"?>\n'
50
Andrew Lamb2413c982020-05-29 12:15:36 -060051
Andrew Lambcd33f702020-06-11 10:45:16 -060052def parse_args(argv):
David Burger7fd1dbe2020-03-26 09:26:55 -060053 """Parse the available arguments.
54
55 Invalid arguments or -h cause this function to print a message and exit.
56
57 Args:
58 argv: List of string arguments (excluding program name / argv[0])
59
60 Returns:
61 argparse.Namespace object containing the attributes.
62 """
63 parser = argparse.ArgumentParser(
64 description='Converts source proto config into platform JSON config.')
65 parser.add_argument(
66 '-c',
67 '--project_configs',
68 nargs='+',
69 type=str,
70 help='Space delimited list of source protobinary project config files.')
71 parser.add_argument(
72 '-p',
73 '--program_config',
74 type=str,
75 help='Path to the source program-level protobinary file')
76 parser.add_argument(
Andrew Lamb2413c982020-05-29 12:15:36 -060077 '-o', '--output', type=str, help='Output file that will be generated')
David Burger7fd1dbe2020-03-26 09:26:55 -060078 return parser.parse_args(argv)
79
80
David Burger8ee9b4d2020-06-16 17:40:21 -060081def _upsert(field, target, target_name):
82 """Updates or inserts `field` within `target`.
83
84 If `target_name` already exists within `target` an update is performed,
85 otherwise, an insert is performed.
86 """
Sam McNally9a873f72020-06-05 19:47:22 +100087 if field or field == 0:
David Burger8ee9b4d2020-06-16 17:40:21 -060088 if target_name in target:
89 target[target_name].update(field)
90 else:
91 target[target_name] = field
David Burger7fd1dbe2020-03-26 09:26:55 -060092
93
Andrew Lambcd33f702020-06-11 10:45:16 -060094def _build_arc(config, config_files):
Andrew Lambcd33f702020-06-11 10:45:16 -060095 build_properties = {
C Shapirod5545f12020-11-30 16:37:04 -060096 # TODO(chromium:1126527) - Push this into the overlay itself.
97 # This isn't/can't be device specific and shouldn't be configured as such.
98 'device': "%s_cheets" % config.program.name.lower(),
99 'first-api-level': '28',
Andrew Lambcd33f702020-06-11 10:45:16 -0600100 'marketing-name': config.device_brand.brand_name,
101 'metrics-tag': config.hw_design.name.lower(),
C Shapirod5545f12020-11-30 16:37:04 -0600102 'product': config.program.name.lower(),
Andrew Lambcd33f702020-06-11 10:45:16 -0600103 }
104 if config.oem:
105 build_properties['oem'] = config.oem.name
106 result = {'build-properties': build_properties}
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800107 config_id = _get_formatted_config_id(config.hw_design_config)
108 if config_id in config_files.arc_hw_features:
109 result['hardware-features'] = config_files.arc_hw_features[config_id]
Ren-Pei Zengacf03be2020-11-11 13:56:51 +0800110 if config_id in config_files.arc_media_profiles:
111 result['media-profiles'] = config_files.arc_media_profiles[config_id]
Andrew Lambcd33f702020-06-11 10:45:16 -0600112 topology = config.hw_design_config.hardware_topology
113 ppi = topology.screen.hardware_feature.screen.panel_properties.pixels_per_in
114 # Only set for high resolution displays
115 if ppi and ppi > 250:
116 result['scale'] = ppi
David Burger2f0d9522020-07-30 10:52:28 -0600117
Andrew Lambcd33f702020-06-11 10:45:16 -0600118 return result
David Burger7fd1dbe2020-03-26 09:26:55 -0600119
Andrew Lamb2413c982020-05-29 12:15:36 -0600120
Andrew Lamb319cc922020-06-15 10:45:46 -0600121def _build_ash_flags(config: Config) -> List[str]:
122 """Returns a list of Ash flags for config.
123
124 Ash is the window manager and system UI for ChromeOS, see
125 https://chromium.googlesource.com/chromium/src/+/refs/heads/master/ash/.
126 """
127 # A map from flag name -> value. Value may be None for boolean flags.
128 flags = {}
129
130 hw_features = config.hw_design_config.hardware_features
131 if hw_features.stylus.stylus == topology_pb2.HardwareFeatures.Stylus.INTERNAL:
Andrew Lamb2e641e22020-06-15 12:30:41 -0600132 flags['has-internal-stylus'] = None
Andrew Lamb319cc922020-06-15 10:45:46 -0600133
Andrew Lamb2e641e22020-06-15 12:30:41 -0600134 fp_loc = hw_features.fingerprint.location
135 if fp_loc and fp_loc != topology_pb2.HardwareFeatures.Fingerprint.NOT_PRESENT:
136 loc_name = topology_pb2.HardwareFeatures.Fingerprint.Location.Name(fp_loc)
137 flags['fingerprint-sensor-location'] = loc_name.lower().replace('_', '-')
138
Andrew Lamb6c42efc2020-06-16 10:40:43 -0600139 wallpaper = config.brand_config.wallpaper
140 # If a wallpaper is set, the 'default-wallpaper-is-oem' flag needs to be set.
141 # If a wallpaper is not set, the 'default_[large|small].jpg' wallpapers
142 # should still be set.
143 if wallpaper:
144 flags['default-wallpaper-is-oem'] = None
145 else:
146 wallpaper = 'default'
147
148 for size in ('small', 'large'):
149 flags[f'default-wallpaper-{size}'] = (
150 f'{WALLPAPER_BASE_PATH}/{wallpaper}_{size}.jpg')
151
152 # For each size, also install 'guest' and 'child' wallpapers.
153 for wallpaper_type in ('guest', 'child'):
154 flags[f'{wallpaper_type}-wallpaper-{size}'] = (
155 f'{WALLPAPER_BASE_PATH}/{wallpaper_type}_{size}.jpg')
156
C Shapiro2e97aad2020-11-16 11:58:10 -0600157 regulatory_label = config.brand_config.regulatory_label
158 if regulatory_label:
159 flags['regulatory-label-dir'] = (regulatory_label)
160
C Shapirod5545f12020-11-30 16:37:04 -0600161 flags['arc-build-properties'] = {
162 'device': "%s_cheets" % config.program.name.lower(),
163 'firstApiLevel': '28',
164 }
Andrew Lamb72d41362020-06-17 09:19:02 -0600165
Andrew Lamb90b168c2020-06-22 10:42:30 -0600166 power_button = hw_features.power_button
167 if power_button.edge:
168 flags['ash-power-button-position'] = json.dumps({
169 'edge':
170 topology_pb2.HardwareFeatures.Button.Edge.Name(power_button.edge
171 ).lower(),
172 # Starlark sometimes represents float literals strangely, e.g. changing
173 # 0.9 to 0.899999. Round to two digits here.
174 'position':
175 round(power_button.position, 2)
176 })
177
178 volume_button = hw_features.volume_button
179 if volume_button.edge:
180 flags['ash-side-volume-button-position'] = json.dumps({
181 'region':
182 topology_pb2.HardwareFeatures.Button.Region.Name(
183 volume_button.region).lower(),
184 'edge':
185 topology_pb2.HardwareFeatures.Button.Edge.Name(volume_button.edge
186 ).lower(),
187 })
188
Nikolai Artemievda87d992020-12-04 15:09:00 +1100189 form_factor = hw_features.form_factor.form_factor
190 lid_accel = hw_features.accelerometer.lid_accelerometer
191 if (form_factor == topology_pb2.HardwareFeatures.FormFactor.CHROMEBASE and
192 lid_accel == topology_pb2.HardwareFeatures.PRESENT):
Nikolai Artemiev03de0e02021-03-23 17:46:49 +1100193 flags['supports-clamshell-auto-rotation'] = None
Nikolai Artemievda87d992020-12-04 15:09:00 +1100194
Andrew Lamb2e641e22020-06-15 12:30:41 -0600195 return sorted([f'--{k}={v}' if v else f'--{k}' for k, v in flags.items()])
Andrew Lamb319cc922020-06-15 10:45:46 -0600196
197
198def _build_ui(config: Config) -> dict:
199 """Builds the 'ui' property from cros_config_schema."""
200 return {'extra-ash-flags': _build_ash_flags(config)}
201
202
David Burger07af5242020-08-11 11:08:25 -0600203def _build_bluetooth(config):
C Shapiro90fda252020-04-17 14:34:57 -0500204 bt_flags = config.sw_config.bluetooth_config.flags
205 # Convert to native map (from proto wrapper)
206 bt_flags_map = dict(bt_flags)
207 result = {}
208 if bt_flags_map:
209 result['flags'] = bt_flags_map
C Shapiro90fda252020-04-17 14:34:57 -0500210 return result
211
David Burger7fd1dbe2020-03-26 09:26:55 -0600212
David Burgerceeb68a2020-09-03 11:31:10 -0600213def _build_ath10k_config(ath10k_config):
214 """Builds the wifi configuration for the ath10k driver.
215
216 Args:
217 ath10k_config: Ath10kConfig config.
218
219 Returns:
220 wifi configuration for the ath10k driver.
221 """
David Burgerec753912020-08-10 12:59:11 -0600222 result = {}
David Burgerec753912020-08-10 12:59:11 -0600223
David Burgerceeb68a2020-09-03 11:31:10 -0600224 def power_chain(power):
225 return {
226 'limit-2g': power.limit_2g,
227 'limit-5g': power.limit_5g,
228 }
David Burgerec753912020-08-10 12:59:11 -0600229
David Burgerceeb68a2020-09-03 11:31:10 -0600230 result['tablet-mode-power-table-ath10k'] = power_chain(
231 ath10k_config.tablet_mode_power_table)
232 result['non-tablet-mode-power-table-ath10k'] = power_chain(
233 ath10k_config.non_tablet_mode_power_table)
David Burgerec753912020-08-10 12:59:11 -0600234 return result
235
236
David Burgerceeb68a2020-09-03 11:31:10 -0600237def _build_rtw88_config(rtw88_config):
238 """Builds the wifi configuration for the rtw88 driver.
239
240 Args:
241 rtw88_config: Rtw88Config config.
242
243 Returns:
244 wifi configuration for the rtw88 driver.
245 """
246 result = {}
247
248 def power_chain(power):
249 return {
250 'limit-2g': power.limit_2g,
251 'limit-5g-1': power.limit_5g_1,
252 'limit-5g-3': power.limit_5g_3,
253 'limit-5g-4': power.limit_5g_4,
254 }
255
256 result['tablet-mode-power-table-rtw'] = power_chain(
257 rtw88_config.tablet_mode_power_table)
258 result['non-tablet-mode-power-table-rtw'] = power_chain(
259 rtw88_config.non_tablet_mode_power_table)
260
261 def offsets(offset):
262 return {
263 'offset-2g': offset.offset_2g,
264 'offset-5g': offset.offset_5g,
265 }
266
267 result['geo-offsets-fcc'] = offsets(rtw88_config.offset_fcc)
268 result['geo-offsets-eu'] = offsets(rtw88_config.offset_eu)
269 result['geo-offsets-rest-of-world'] = offsets(rtw88_config.offset_other)
270 return result
271
272
273def _build_intel_config(config, config_files):
274 """Builds the wifi configuration for the intel driver.
275
276 Args:
277 config: Config namedtuple
278 config_files: Map to look up the generated config files.
279
280 Returns:
281 wifi configuration for the intel driver.
282 """
283 design_name = config.hw_design.name.lower()
284 return config_files.wifi_sar_map.get(design_name)
285
286
287def _build_wifi(config, config_files):
288 """Builds the wifi configuration.
289
290 Args:
291 config: Config namedtuple
292 config_files: Map to look up the generated config files.
293
294 Returns:
295 wifi configuration.
296 """
297 config_field = config.sw_config.wifi_config.WhichOneof('wifi_config')
298 if config_field == 'ath10k_config':
299 return _build_ath10k_config(config.sw_config.wifi_config.ath10k_config)
300 if config_field == 'rtw88_config':
301 return _build_rtw88_config(config.sw_config.wifi_config.rtw88_config)
302 if config_field == 'intel_config':
303 return _build_intel_config(config, config_files)
304 return {}
305
306
Andrew Lambcd33f702020-06-11 10:45:16 -0600307def _build_fingerprint(hw_topology):
308 if not hw_topology.HasField('fingerprint'):
309 return None
310
311 fp = hw_topology.fingerprint.hardware_feature.fingerprint
312 result = {}
313 if fp.location != topology_pb2.HardwareFeatures.Fingerprint.NOT_PRESENT:
314 location = fp.Location.DESCRIPTOR.values_by_number[fp.location].name
315 result['sensor-location'] = location.lower().replace('_', '-')
316 if fp.board:
317 result['board'] = fp.board
Tom Hughesdfc35402020-06-29 16:02:09 -0700318 if fp.ro_version:
319 result['ro-version'] = fp.ro_version
320
Andrew Lambcd33f702020-06-11 10:45:16 -0600321 return result
David Burger7fd1dbe2020-03-26 09:26:55 -0600322
323
Trent Beginf067ccb2020-08-12 12:33:53 -0600324def _build_hardware_properties(hw_topology):
325 if not hw_topology.HasField('form_factor'):
326 return None
327
328 form_factor = hw_topology.form_factor.hardware_feature.form_factor.form_factor
329 result = {}
330 if form_factor in [
331 topology_pb2.HardwareFeatures.FormFactor.CHROMEBIT,
332 topology_pb2.HardwareFeatures.FormFactor.CHROMEBASE,
333 topology_pb2.HardwareFeatures.FormFactor.CHROMEBOX
334 ]:
335 result['psu-type'] = "AC_only"
336 else:
337 result['psu-type'] = "battery"
338
339 result['has-backlight'] = form_factor not in [
340 topology_pb2.HardwareFeatures.FormFactor.CHROMEBIT,
341 topology_pb2.HardwareFeatures.FormFactor.CHROMEBOX
342 ]
343
Nikolai Artemiev1be27ef2021-01-11 17:32:17 +1100344 form_factor_names = {
Nikolai Artemievaf103a32021-02-15 14:37:16 +1100345 topology_pb2.HardwareFeatures.FormFactor.CLAMSHELL: "CHROMEBOOK",
346 topology_pb2.HardwareFeatures.FormFactor.CONVERTIBLE: "CHROMEBOOK",
347 topology_pb2.HardwareFeatures.FormFactor.DETACHABLE: "CHROMEBOOK",
Nikolai Artemiev1be27ef2021-01-11 17:32:17 +1100348 topology_pb2.HardwareFeatures.FormFactor.CHROMEBASE: "CHROMEBASE",
Nikolai Artemievaf103a32021-02-15 14:37:16 +1100349 topology_pb2.HardwareFeatures.FormFactor.CHROMEBOX: "CHROMEBOX",
350 topology_pb2.HardwareFeatures.FormFactor.CHROMEBIT: "CHROMEBIT",
351 topology_pb2.HardwareFeatures.FormFactor.CHROMESLATE: "CHROMEBOOK",
Nikolai Artemiev1be27ef2021-01-11 17:32:17 +1100352 }
353 if form_factor in form_factor_names:
354 result['form-factor'] = form_factor_names[form_factor]
355
Trent Beginf067ccb2020-08-12 12:33:53 -0600356 return result
357
358
Andrew Lambcd33f702020-06-11 10:45:16 -0600359def _fw_bcs_path(payload):
David Burger7fd1dbe2020-03-26 09:26:55 -0600360 if payload and payload.firmware_image_name:
YH Lin873742a2021-03-02 07:02:31 -0800361 return 'bcs://%s.%d.%d.%d.tbz2' % (
362 payload.firmware_image_name, payload.version.major,
363 payload.version.minor, payload.version.patch)
David Burger7fd1dbe2020-03-26 09:26:55 -0600364
Andrew Lambcd33f702020-06-11 10:45:16 -0600365 return None
David Burger7fd1dbe2020-03-26 09:26:55 -0600366
Andrew Lambcd33f702020-06-11 10:45:16 -0600367
368def _fw_build_target(payload):
David Burger7fd1dbe2020-03-26 09:26:55 -0600369 if payload:
370 return payload.build_target_name
371
Andrew Lambcd33f702020-06-11 10:45:16 -0600372 return None
David Burger7fd1dbe2020-03-26 09:26:55 -0600373
Andrew Lambcd33f702020-06-11 10:45:16 -0600374
375def _build_firmware(config):
David Burgerb70b6762020-05-21 12:14:59 -0600376 """Returns firmware config, or None if no build targets."""
Andrew Lamb3da156d2020-04-16 16:00:56 -0600377 fw_payload_config = config.sw_config.firmware
378 fw_build_config = config.sw_config.firmware_build_config
379 main_ro = fw_payload_config.main_ro_payload
380 main_rw = fw_payload_config.main_rw_payload
381 ec_ro = fw_payload_config.ec_ro_payload
382 pd_ro = fw_payload_config.pd_ro_payload
David Burger7fd1dbe2020-03-26 09:26:55 -0600383
384 build_targets = {}
Andrew Lamb3da156d2020-04-16 16:00:56 -0600385
David Burger8ee9b4d2020-06-16 17:40:21 -0600386 _upsert(fw_build_config.build_targets.depthcharge, build_targets,
387 'depthcharge')
388 _upsert(fw_build_config.build_targets.coreboot, build_targets, 'coreboot')
389 _upsert(fw_build_config.build_targets.ec, build_targets, 'ec')
390 _upsert(
Andrew Lambf8954ee2020-04-21 10:24:40 -0600391 list(fw_build_config.build_targets.ec_extras), build_targets, 'ec_extras')
David Burger8ee9b4d2020-06-16 17:40:21 -0600392 _upsert(fw_build_config.build_targets.libpayload, build_targets, 'libpayload')
David Burger7fd1dbe2020-03-26 09:26:55 -0600393
David Burgerb70b6762020-05-21 12:14:59 -0600394 if not build_targets:
395 return None
396
David Burger7fd1dbe2020-03-26 09:26:55 -0600397 result = {
C Shapirod5545f12020-11-30 16:37:04 -0600398 'bcs-overlay': 'overlay-%s-private' % config.program.name.lower(),
David Burger7fd1dbe2020-03-26 09:26:55 -0600399 'build-targets': build_targets,
David Burger7fd1dbe2020-03-26 09:26:55 -0600400 }
Andrew Lamb883fa042020-04-06 11:37:22 -0600401
David Burger8ee9b4d2020-06-16 17:40:21 -0600402 _upsert(main_ro.firmware_image_name.lower(), result, 'image-name')
Andrew Lamb883fa042020-04-06 11:37:22 -0600403
David Burger8ee9b4d2020-06-16 17:40:21 -0600404 _upsert(_fw_bcs_path(main_ro), result, 'main-ro-image')
405 _upsert(_fw_bcs_path(main_rw), result, 'main-rw-image')
406 _upsert(_fw_bcs_path(ec_ro), result, 'ec-ro-image')
407 _upsert(_fw_bcs_path(pd_ro), result, 'pd-ro-image')
David Burger7fd1dbe2020-03-26 09:26:55 -0600408
David Burger8ee9b4d2020-06-16 17:40:21 -0600409 _upsert(
Andrew Lambf39fbe82020-04-13 16:14:33 -0600410 config.hw_design_config.hardware_features.fw_config.value,
411 result,
412 'firmware-config',
413 )
414
David Burger7fd1dbe2020-03-26 09:26:55 -0600415 return result
416
417
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000418def _build_fw_signing(config, whitelabel):
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500419 if config.sw_config.firmware and config.device_signer_config:
David Burger68e0d142020-05-15 17:29:33 -0600420 hw_design = config.hw_design.name.lower()
Sam McNally2fc807f2020-07-16 18:13:53 +1000421 brand_scan_config = config.brand_config.scan_config
422 if brand_scan_config and brand_scan_config.whitelabel_tag:
423 signature_id = '%s-%s' % (hw_design, brand_scan_config.whitelabel_tag)
424 else:
425 signature_id = hw_design
426
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000427 result = {
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500428 'key-id': config.device_signer_config.key_id,
Sam McNally2fc807f2020-07-16 18:13:53 +1000429 'signature-id': signature_id,
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500430 }
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000431 if whitelabel:
432 result['sig-id-in-customization-id'] = True
433 return result
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500434 return {}
David Burger7fd1dbe2020-03-26 09:26:55 -0600435
436
Andrew Lambcd33f702020-06-11 10:45:16 -0600437def _file(source, destination):
Andrew Lamb2413c982020-05-29 12:15:36 -0600438 return {'destination': destination, 'source': source}
David Burger7fd1dbe2020-03-26 09:26:55 -0600439
440
David Burger40dfe3a2020-06-18 17:09:13 -0600441def _file_v2(build_path, system_path):
442 return {'build-path': build_path, 'system-path': system_path}
443
444
Andrew Lambcd33f702020-06-11 10:45:16 -0600445def _build_audio(config):
David Burger178f3ef2020-06-26 12:11:57 -0600446 if not config.sw_config.audio_configs:
447 return {}
David Burger7fd1dbe2020-03-26 09:26:55 -0600448 alsa_path = '/usr/share/alsa/ucm'
449 cras_path = '/etc/cras'
Judy Hsiao1ae95122020-12-23 15:39:50 +0800450 sound_card_init_path = '/etc/sound_card_init'
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800451 design_name = config.hw_design.name.lower()
David Burger43250662020-05-07 11:21:50 -0600452 program_name = config.program.name.lower()
David Burger7fd1dbe2020-03-26 09:26:55 -0600453 files = []
David Burger178f3ef2020-06-26 12:11:57 -0600454 ucm_suffix = None
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800455 sound_card_init_conf = None
456
David Burger178f3ef2020-06-26 12:11:57 -0600457 for audio in config.sw_config.audio_configs:
458 card = audio.card_name
459 card_with_suffix = audio.card_name
460 if audio.ucm_suffix:
461 # TODO: last ucm_suffix wins.
462 ucm_suffix = audio.ucm_suffix
463 card_with_suffix += '.' + audio.ucm_suffix
464 if audio.ucm_file:
465 files.append(
466 _file(audio.ucm_file,
467 '%s/%s/HiFi.conf' % (alsa_path, card_with_suffix)))
468 if audio.ucm_master_file:
469 files.append(
470 _file(
471 audio.ucm_master_file, '%s/%s/%s.conf' %
Andrew Lamb2413c982020-05-29 12:15:36 -0600472 (alsa_path, card_with_suffix, card_with_suffix)))
David Burger178f3ef2020-06-26 12:11:57 -0600473 if audio.card_config_file:
474 files.append(
475 _file(audio.card_config_file,
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800476 '%s/%s/%s' % (cras_path, design_name, card)))
David Burger178f3ef2020-06-26 12:11:57 -0600477 if audio.dsp_file:
478 files.append(
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800479 _file(audio.dsp_file, '%s/%s/dsp.ini' % (cras_path, design_name)))
David Burger178f3ef2020-06-26 12:11:57 -0600480 if audio.module_file:
481 files.append(
482 _file(audio.module_file,
483 '/etc/modprobe.d/alsa-%s.conf' % program_name))
484 if audio.board_file:
485 files.append(
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800486 _file(audio.board_file, '%s/%s/board.ini' % (cras_path, design_name)))
Judy Hsiao1ae95122020-12-23 15:39:50 +0800487 if audio.sound_card_init_file:
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800488 sound_card_init_conf = design_name + ".yaml"
Judy Hsiao1ae95122020-12-23 15:39:50 +0800489 files.append(
490 _file(audio.sound_card_init_file,
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800491 '%s/%s.yaml' % (sound_card_init_path, design_name)))
David Burger599ff7b2020-04-06 16:29:31 -0600492
493 result = {
David Burger7fd1dbe2020-03-26 09:26:55 -0600494 'main': {
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800495 'cras-config-dir': design_name,
David Burger7fd1dbe2020-03-26 09:26:55 -0600496 'files': files,
497 }
498 }
David Burger178f3ef2020-06-26 12:11:57 -0600499
500 if ucm_suffix:
501 result['main']['ucm-suffix'] = ucm_suffix
Judy Hsiao5ab0d8e2021-03-04 16:17:18 +0800502 if sound_card_init_conf:
503 result['main']['sound-card-init-conf'] = sound_card_init_conf
David Burger599ff7b2020-04-06 16:29:31 -0600504
505 return result
David Burger7fd1dbe2020-03-26 09:26:55 -0600506
507
Andrew Lambcd33f702020-06-11 10:45:16 -0600508def _build_camera(hw_topology):
Ren-Pei Zeng573d6332020-11-12 14:55:22 +0800509 camera_pb = topology_pb2.HardwareFeatures.Camera
510 camera = hw_topology.camera.hardware_feature.camera
511 result = {'count': len(camera.devices)}
512 if camera.devices:
513 result['devices'] = []
514 for device in camera.devices:
515 interface = {
516 camera_pb.INTERFACE_USB: 'usb',
517 camera_pb.INTERFACE_MIPI: 'mipi',
518 }[device.interface]
519 facing = {
520 camera_pb.FACING_FRONT: 'front',
521 camera_pb.FACING_BACK: 'back',
522 }[device.facing]
523 orientation = {
524 camera_pb.ORIENTATION_0: 0,
525 camera_pb.ORIENTATION_90: 90,
526 camera_pb.ORIENTATION_180: 180,
527 camera_pb.ORIENTATION_270: 270,
528 }[device.orientation]
529 flags = {
530 'support-1080p':
531 bool(device.flags & camera_pb.FLAGS_SUPPORT_1080P),
532 'support-autofocus':
533 bool(device.flags & camera_pb.FLAGS_SUPPORT_AUTOFOCUS),
534 }
Ricardo Ribaldab9b17b32021-01-13 17:10:20 +0100535 dev = {
Ren-Pei Zeng573d6332020-11-12 14:55:22 +0800536 'interface': interface,
537 'facing': facing,
538 'orientation': orientation,
539 'flags': flags,
540 'ids': list(device.ids),
Ricardo Ribaldab9b17b32021-01-13 17:10:20 +0100541 }
542 if device.privacy_switch != topology_pb2.HardwareFeatures.PRESENT_UNKNOWN:
543 dev['has-privacy-switch'] = device.privacy_switch == topology_pb2.HardwareFeatures.PRESENT
544 result['devices'].append(dev)
Ren-Pei Zeng573d6332020-11-12 14:55:22 +0800545 return result
David Burger8aa8fa32020-04-14 08:30:34 -0600546
Andrew Lambcd33f702020-06-11 10:45:16 -0600547
548def _build_identity(hw_scan_config, program, brand_scan_config=None):
David Burger7fd1dbe2020-03-26 09:26:55 -0600549 identity = {}
David Burger8ee9b4d2020-06-16 17:40:21 -0600550 _upsert(hw_scan_config.firmware_sku, identity, 'sku-id')
551 _upsert(hw_scan_config.smbios_name_match, identity, 'smbios-name-match')
Andrew Lamb7806ce92020-04-07 10:22:17 -0600552 # 'platform-name' is needed to support 'mosys platform name'. Clients should
Sean McAllister0b757772020-11-13 12:22:36 -0700553 # no longer require platform name, but set it here for backwards compatibility.
554 if program.mosys_platform_name:
555 _upsert(program.mosys_platform_name, identity, 'platform-name')
556 else:
557 _upsert(program.name, identity, 'platform-name')
558
David Burger7fd1dbe2020-03-26 09:26:55 -0600559 # ARM architecture
David Burger8ee9b4d2020-06-16 17:40:21 -0600560 _upsert(hw_scan_config.device_tree_compatible_match, identity,
561 'device-tree-compatible-match')
David Burger7fd1dbe2020-03-26 09:26:55 -0600562
563 if brand_scan_config:
David Burger8ee9b4d2020-06-16 17:40:21 -0600564 _upsert(brand_scan_config.whitelabel_tag, identity, 'whitelabel-tag')
David Burger7fd1dbe2020-03-26 09:26:55 -0600565
566 return identity
567
568
Andrew Lambcd33f702020-06-11 10:45:16 -0600569def _lookup(id_value, id_map):
570 if not id_value.value:
571 return None
572
573 key = id_value.value
574 if key in id_map:
575 return id_map[id_value.value]
576 error = 'Failed to lookup %s with value: %s' % (
577 id_value.__class__.__name__.replace('Id', ''), key)
578 print(error)
579 print('Check the config contents provided:')
580 printer = pprint.PrettyPrinter(indent=4)
581 printer.pprint(id_map)
582 raise Exception(error)
David Burger7fd1dbe2020-03-26 09:26:55 -0600583
584
Andrew Lambcd33f702020-06-11 10:45:16 -0600585def _build_touch_file_config(config, project_name):
Sean McAllistereaf10b72020-08-03 13:41:06 -0600586 partners = {x.id.value: x for x in config.partner_list}
C Shapiro2b6d5332020-05-06 17:51:35 -0500587 files = []
588 for comp in config.components:
C Shapiro4813be62020-05-13 17:31:58 -0500589 touch = comp.touchscreen
590 # Everything is the same for Touch screen/pad, except different fields
591 if comp.HasField('touchpad'):
592 touch = comp.touchpad
593 if touch.product_id:
Andrew Lambcd33f702020-06-11 10:45:16 -0600594 vendor = _lookup(comp.manufacturer_id, partners)
C Shapiro2b6d5332020-05-06 17:51:35 -0500595 if not vendor:
Andrew Lamb2413c982020-05-29 12:15:36 -0600596 raise Exception("Manufacturer must be set for touch device %s" %
597 comp.id.value)
C Shapiro2b6d5332020-05-06 17:51:35 -0500598
C Shapiro4813be62020-05-13 17:31:58 -0500599 product_id = touch.product_id
600 fw_version = touch.fw_version
C Shapiro2b6d5332020-05-06 17:51:35 -0500601
C Shapiro2b6d5332020-05-06 17:51:35 -0500602 file_name = "%s_%s.bin" % (product_id, fw_version)
603 fw_file_path = os.path.join(TOUCH_PATH, vendor.name, file_name)
604
605 if not os.path.exists(fw_file_path):
Andrew Lamb2413c982020-05-29 12:15:36 -0600606 raise Exception("Touchscreen fw bin file doesn't exist at: %s" %
607 fw_file_path)
C Shapiro2b6d5332020-05-06 17:51:35 -0500608
C Shapiro303cece2020-07-22 07:15:21 -0500609 touch_vendor = vendor.touch_vendor
610 sym_link = touch_vendor.symlink_file_format.format(
611 vendor_name=vendor.name,
612 vendor_id=touch_vendor.vendor_id,
613 product_id=product_id,
614 fw_version=fw_version,
615 product_series=touch.product_series)
616
617 dest = "%s_%s" % (vendor.name, file_name)
618 if touch_vendor.destination_file_format:
619 dest = touch_vendor.destination_file_format.format(
620 vendor_name=vendor.name,
621 vendor_id=touch_vendor.vendor_id,
622 product_id=product_id,
623 fw_version=fw_version,
624 product_series=touch.product_series)
625
C Shapiro2b6d5332020-05-06 17:51:35 -0500626 files.append({
C Shapiro303cece2020-07-22 07:15:21 -0500627 "destination": os.path.join("/opt/google/touch/firmware", dest),
YH Lin9160fc52020-07-22 16:35:28 -0700628 "source": os.path.join(project_name, fw_file_path),
629 "symlink": os.path.join("/lib/firmware", sym_link),
C Shapiro2b6d5332020-05-06 17:51:35 -0500630 })
631
632 result = {}
David Burger8ee9b4d2020-06-16 17:40:21 -0600633 _upsert(files, result, 'files')
C Shapiro2b6d5332020-05-06 17:51:35 -0500634 return result
635
636
Vincent Palatin2ef6bd62021-01-04 14:47:31 +0000637def _build_modem(config):
638 """Returns the cellular modem configuration, or None if absent."""
639 hw_features = config.hw_design_config.hardware_features
640 lte_support = _any_present([hw_features.lte.present])
641 if not lte_support:
642 return None
643 return {'firmware-variant': config.hw_design.name.lower()}
644
645
David Burgerceeb68a2020-09-03 11:31:10 -0600646def _sw_config(sw_configs, design_config_id):
647 """Returns the correct software config for `design_config_id`.
648
649 Returns the correct software config match for `design_config_id`. If no such
650 config or multiple such configs are found an exception is raised.
651 """
652 sw_config_matches = [
653 x for x in sw_configs if x.design_config_id.value == design_config_id
654 ]
655 if len(sw_config_matches) == 1:
656 return sw_config_matches[0]
657 if len(sw_config_matches) > 1:
658 raise ValueError('Multiple software configs found for: %s' %
659 design_config_id)
660 raise ValueError('Software config is required for: %s' % design_config_id)
661
662
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000663def _is_whitelabel(brand_configs, device_brands):
664 for device_brand in device_brands:
665 if device_brand.id.value in brand_configs:
666 brand_scan_config = brand_configs[device_brand.id.value].scan_config
667 if brand_scan_config and brand_scan_config.whitelabel_tag:
668 return True
669 return False
670
671
David Burgerceeb68a2020-09-03 11:31:10 -0600672def _transform_build_configs(config,
Ren-Pei Zengacf03be2020-11-11 13:56:51 +0800673 config_files=ConfigFiles({}, {}, {}, {}, {}, {})):
Andrew Lambcd33f702020-06-11 10:45:16 -0600674 # pylint: disable=too-many-locals,too-many-branches
Sean McAllistereaf10b72020-08-03 13:41:06 -0600675 partners = {x.id.value: x for x in config.partner_list}
Sean McAllisterf38d1e92020-08-03 13:57:53 -0600676 programs = {x.id.value: x for x in config.program_list}
David Burger7fd1dbe2020-03-26 09:26:55 -0600677 sw_configs = list(config.software_configs)
Andrew Lambcd33f702020-06-11 10:45:16 -0600678 brand_configs = {x.brand_id.value: x for x in config.brand_configs}
David Burger7fd1dbe2020-03-26 09:26:55 -0600679
680 results = {}
Sean McAllisterf66887b2020-08-03 14:00:51 -0600681 for hw_design in config.design_list:
Sean McAllister6cbb0ec2020-08-03 14:03:37 -0600682 if config.device_brand_list:
Andrew Lamb2413c982020-05-29 12:15:36 -0600683 device_brands = [
Sean McAllister6cbb0ec2020-08-03 14:03:37 -0600684 x for x in config.device_brand_list
Andrew Lamb2413c982020-05-29 12:15:36 -0600685 if x.design_id.value == hw_design.id.value
686 ]
David Burger7fd1dbe2020-03-26 09:26:55 -0600687 else:
688 device_brands = [device_brand_pb2.DeviceBrand()]
689
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000690 whitelabel = _is_whitelabel(brand_configs, device_brands)
691
David Burger7fd1dbe2020-03-26 09:26:55 -0600692 for device_brand in device_brands:
693 # Brand config can be empty since platform JSON config allows it
694 brand_config = brand_config_pb2.BrandConfig()
695 if device_brand.id.value in brand_configs:
696 brand_config = brand_configs[device_brand.id.value]
697
698 for hw_design_config in hw_design.configs:
David Burgerceeb68a2020-09-03 11:31:10 -0600699 sw_config = _sw_config(sw_configs, hw_design_config.id.value)
Andrew Lambcd33f702020-06-11 10:45:16 -0600700 program = _lookup(hw_design.program_id, programs)
C Shapiroadefd7c2020-05-19 16:37:21 -0500701 signer_configs_by_design = {}
702 signer_configs_by_brand = {}
703 for signer_config in program.device_signer_configs:
704 design_id = signer_config.design_id.value
705 brand_id = signer_config.brand_id.value
706 if design_id:
707 signer_configs_by_design[design_id] = signer_config
708 elif brand_id:
709 signer_configs_by_brand[brand_id] = signer_config
710 else:
711 raise Exception('No ID found for signer config: %s' % signer_config)
712
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500713 device_signer_config = None
C Shapiroadefd7c2020-05-19 16:37:21 -0500714 if signer_configs_by_design or signer_configs_by_brand:
715 design_id = hw_design.id.value
716 brand_id = device_brand.id.value
717 if design_id in signer_configs_by_design:
718 device_signer_config = signer_configs_by_design[design_id]
719 elif brand_id in signer_configs_by_brand:
720 device_signer_config = signer_configs_by_brand[brand_id]
721 else:
722 # Assume that if signer configs are set, every config is setup
Andrew Lamb2413c982020-05-29 12:15:36 -0600723 raise Exception('Signer config missing for design: %s, brand: %s' %
724 (design_id, brand_id))
C Shapiro2f0bb5d2020-04-14 10:07:47 -0500725
Andrew Lambcd33f702020-06-11 10:45:16 -0600726 transformed_config = _transform_build_config(
C Shapiro90fda252020-04-17 14:34:57 -0500727 Config(
728 program=program,
729 hw_design=hw_design,
Andrew Lambcd33f702020-06-11 10:45:16 -0600730 odm=_lookup(hw_design.odm_id, partners),
C Shapiro90fda252020-04-17 14:34:57 -0500731 hw_design_config=hw_design_config,
732 device_brand=device_brand,
733 device_signer_config=device_signer_config,
Andrew Lambcd33f702020-06-11 10:45:16 -0600734 oem=_lookup(device_brand.oem_id, partners),
C Shapiro90fda252020-04-17 14:34:57 -0500735 sw_config=sw_config,
C Shapirod5545f12020-11-30 16:37:04 -0600736 brand_config=brand_config), config_files, whitelabel)
David Burger7fd1dbe2020-03-26 09:26:55 -0600737
Andrew Lamb2413c982020-05-29 12:15:36 -0600738 config_json = json.dumps(
739 transformed_config,
740 sort_keys=True,
741 indent=2,
742 separators=(',', ': '))
David Burger7fd1dbe2020-03-26 09:26:55 -0600743
744 if config_json not in results:
745 results[config_json] = transformed_config
746
747 return list(results.values())
748
749
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000750def _transform_build_config(config, config_files, whitelabel):
David Burger7fd1dbe2020-03-26 09:26:55 -0600751 """Transforms Config instance into target platform JSON schema.
752
753 Args:
754 config: Config namedtuple
C Shapiro5bf23a72020-04-24 11:40:17 -0500755 config_files: Map to look up the generated config files.
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000756 whitelabel: Whether the config is for a whitelabel design
David Burger7fd1dbe2020-03-26 09:26:55 -0600757
758 Returns:
759 Unique config payload based on the platform JSON schema.
760 """
761 result = {
Andrew Lamb2413c982020-05-29 12:15:36 -0600762 'identity':
Andrew Lambcd33f702020-06-11 10:45:16 -0600763 _build_identity(config.sw_config.id_scan_config, config.program,
764 config.brand_config.scan_config),
Andrew Lamb2413c982020-05-29 12:15:36 -0600765 'name':
766 config.hw_design.name.lower(),
David Burger7fd1dbe2020-03-26 09:26:55 -0600767 }
768
David Burger8ee9b4d2020-06-16 17:40:21 -0600769 _upsert(_build_arc(config, config_files), result, 'arc')
770 _upsert(_build_audio(config), result, 'audio')
David Burger07af5242020-08-11 11:08:25 -0600771 _upsert(_build_bluetooth(config), result, 'bluetooth')
David Burgerceeb68a2020-09-03 11:31:10 -0600772 _upsert(_build_wifi(config, config_files), result, 'wifi')
Andrew Lambca279902020-08-06 10:13:42 -0600773 _upsert(config.brand_config.wallpaper, result, 'wallpaper')
C Shapiro2e97aad2020-11-16 11:58:10 -0600774 _upsert(config.brand_config.regulatory_label, result, 'regulatory-label')
David Burger8ee9b4d2020-06-16 17:40:21 -0600775 _upsert(config.device_brand.brand_code, result, 'brand-code')
776 _upsert(
Andrew Lambcd33f702020-06-11 10:45:16 -0600777 _build_camera(config.hw_design_config.hardware_topology), result,
778 'camera')
David Burger8ee9b4d2020-06-16 17:40:21 -0600779 _upsert(_build_firmware(config), result, 'firmware')
Sam McNallyfd14e4b2020-09-12 10:26:35 +1000780 _upsert(_build_fw_signing(config, whitelabel), result, 'firmware-signing')
David Burger8ee9b4d2020-06-16 17:40:21 -0600781 _upsert(
Andrew Lambcd33f702020-06-11 10:45:16 -0600782 _build_fingerprint(config.hw_design_config.hardware_topology), result,
Andrew Lamb2413c982020-05-29 12:15:36 -0600783 'fingerprint')
Andrew Lamb0d236ab2020-06-30 12:30:20 -0600784 _upsert(_build_ui(config), result, 'ui')
David Burger7fd1dbe2020-03-26 09:26:55 -0600785 power_prefs = config.sw_config.power_config.preferences
786 power_prefs_map = dict(
Andrew Lamb2413c982020-05-29 12:15:36 -0600787 (x.replace('_', '-'), power_prefs[x]) for x in power_prefs)
David Burger8ee9b4d2020-06-16 17:40:21 -0600788 _upsert(power_prefs_map, result, 'power')
789 if config_files.camera_map:
790 camera_file = config_files.camera_map.get(config.hw_design.name, {})
791 _upsert(camera_file, result, 'camera')
David Burger52c9d322020-06-09 07:16:18 -0600792 if config_files.dptf_map:
793 # Prefer design specific if found, if not fall back to project wide config
794 # mapped under the empty string.
795 if config_files.dptf_map.get(config.hw_design.name):
796 dptf_file = config_files.dptf_map[config.hw_design.name]
797 else:
798 dptf_file = config_files.dptf_map.get('')
David Burger8ee9b4d2020-06-16 17:40:21 -0600799 _upsert(dptf_file, result, 'thermal')
800 _upsert(config_files.touch_fw, result, 'touch')
Trent Beginf067ccb2020-08-12 12:33:53 -0600801 _upsert(
802 _build_hardware_properties(config.hw_design_config.hardware_topology),
803 result, 'hardware-properties')
Vincent Palatin2ef6bd62021-01-04 14:47:31 +0000804 _upsert(_build_modem(config), result, 'modem')
David Burger7fd1dbe2020-03-26 09:26:55 -0600805
806 return result
807
808
Andrew Lambcd33f702020-06-11 10:45:16 -0600809def write_output(configs, output=None):
David Burger7fd1dbe2020-03-26 09:26:55 -0600810 """Writes a list of configs to platform JSON format.
811
812 Args:
813 configs: List of config dicts defined in cros_config_schema.yaml
814 output: Target file output (if None, prints to stdout)
815 """
Andrew Lamb2413c982020-05-29 12:15:36 -0600816 json_output = json.dumps({'chromeos': {
817 'configs': configs,
818 }},
819 sort_keys=True,
820 indent=2,
821 separators=(',', ': '))
David Burger7fd1dbe2020-03-26 09:26:55 -0600822 if output:
823 with open(output, 'w') as output_stream:
824 # Using print function adds proper trailing newline.
825 print(json_output, file=output_stream)
826 else:
827 print(json_output)
828
829
Andrew Lambcd33f702020-06-11 10:45:16 -0600830def _feature(name, present):
C Shapiro5bf23a72020-04-24 11:40:17 -0500831 attrib = {'name': name}
832 if present:
833 return etree.Element('feature', attrib=attrib)
Andrew Lambcd33f702020-06-11 10:45:16 -0600834
835 return etree.Element('unavailable-feature', attrib=attrib)
C Shapiro5bf23a72020-04-24 11:40:17 -0500836
837
Andrew Lambcd33f702020-06-11 10:45:16 -0600838def _any_present(features):
Andrew Lamb2413c982020-05-29 12:15:36 -0600839 return topology_pb2.HardwareFeatures.PRESENT in features
C Shapiro5bf23a72020-04-24 11:40:17 -0500840
841
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800842def _get_formatted_config_id(design_config):
C Shapiro5bf23a72020-04-24 11:40:17 -0500843 return design_config.id.value.lower().replace(':', '_')
844
845
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800846def _write_file(output_dir, file_name, file_content):
David Burger77a1d312020-05-23 16:05:45 -0600847 os.makedirs(output_dir, exist_ok=True)
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800848 output = '{}/{}'.format(output_dir, file_name)
C Shapiroea33cff2020-05-11 13:32:05 -0500849 with open(output, 'wb') as f:
850 f.write(file_content)
851
852
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800853def _get_arc_camera_features(camera):
854 """Gets camera related features for ARC hardware_features.xml from camera
855 topology. Check
856 https://developer.android.com/reference/android/content/pm/PackageManager#FEATURE_CAMERA
857 and CTS android.app.cts.SystemFeaturesTest#testCameraFeatures for the correct
858 settings.
859
860 Args:
861 camera: A HardwareFeatures.Camera proto message.
862 Returns:
863 list of camera related ARC features as XML elements.
864 """
865 camera_pb = topology_pb2.HardwareFeatures.Camera
866
Ren-Pei Zeng9b5682d2020-10-14 17:37:30 +0800867 count = len(camera.devices)
868 has_front_camera = any(
869 (d.facing == camera_pb.FACING_FRONT for d in camera.devices))
870 has_back_camera = any(
871 (d.facing == camera_pb.FACING_BACK for d in camera.devices))
872 has_autofocus_back_camera = any((d.facing == camera_pb.FACING_BACK and
873 d.flags & camera_pb.FLAGS_SUPPORT_AUTOFOCUS
874 for d in camera.devices))
875 # Assumes MIPI cameras support FULL-level.
876 # TODO(kamesan): Setting this in project configs when there's an exception.
877 has_level_full_camera = any(
878 (d.interface == camera_pb.INTERFACE_MIPI for d in camera.devices))
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800879
Ren-Pei Zengf22b5382020-09-02 13:31:22 +0800880 return [
881 _feature('android.hardware.camera', has_back_camera),
882 _feature('android.hardware.camera.any', count > 0),
883 _feature('android.hardware.camera.autofocus', has_autofocus_back_camera),
884 _feature('android.hardware.camera.capability.manual_post_processing',
885 has_level_full_camera),
886 _feature('android.hardware.camera.capability.manual_sensor',
887 has_level_full_camera),
888 _feature('android.hardware.camera.front', has_front_camera),
889 _feature('android.hardware.camera.level.full', has_level_full_camera),
890 ]
891
892
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800893def _generate_arc_hardware_features(hw_features):
894 """Generates ARC hardware_features.xml file content.
C Shapiro5bf23a72020-04-24 11:40:17 -0500895
896 Args:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800897 hw_features: HardwareFeatures proto message.
C Shapiro5bf23a72020-04-24 11:40:17 -0500898 Returns:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800899 bytes of the hardware_features.xml content.
C Shapiro5bf23a72020-04-24 11:40:17 -0500900 """
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +0800901 touchscreen = _any_present([hw_features.screen.touch_support])
902 acc = hw_features.accelerometer
903 gyro = hw_features.gyroscope
904 compass = hw_features.magnetometer
905 light_sensor = hw_features.light_sensor
906 root = etree.Element('permissions')
907 root.extend(
908 _get_arc_camera_features(hw_features.camera) + [
909 _feature(
910 'android.hardware.sensor.accelerometer',
911 _any_present([acc.lid_accelerometer, acc.base_accelerometer])),
912 _feature('android.hardware.sensor.gyroscope',
913 _any_present([gyro.lid_gyroscope, gyro.base_gyroscope])),
914 _feature(
915 'android.hardware.sensor.compass',
916 _any_present(
917 [compass.lid_magnetometer, compass.base_magnetometer])),
918 _feature(
919 'android.hardware.sensor.light',
920 _any_present([
921 light_sensor.lid_lightsensor, light_sensor.base_lightsensor
922 ])),
923 _feature('android.hardware.touchscreen', touchscreen),
924 _feature('android.hardware.touchscreen.multitouch', touchscreen),
925 _feature('android.hardware.touchscreen.multitouch.distinct',
926 touchscreen),
927 _feature('android.hardware.touchscreen.multitouch.jazzhand',
928 touchscreen),
929 ])
Ren-Pei Zengacf03be2020-11-11 13:56:51 +0800930 return XML_DECLARATION + etree.tostring(root, pretty_print=True)
931
932
933def _generate_arc_media_profiles(hw_features, sw_config):
934 """Generates ARC media_profiles.xml file content.
935
936 Args:
937 hw_features: HardwareFeatures proto message.
938 sw_config: SoftwareConfig proto message.
939 Returns:
940 bytes of the media_profiles.xml content, or None if |sw_config| disables the
Ren-Pei Zengb55e4312020-11-18 17:03:01 +0800941 generation or there's no camera.
Ren-Pei Zengacf03be2020-11-11 13:56:51 +0800942 """
943
944 def _gen_camcorder_profiles(camera_id, resolutions):
945 elem = etree.Element(
946 'CamcorderProfiles', attrib={'cameraId': str(camera_id)})
947 for width, height in resolutions:
948 elem.extend([
949 _gen_encoder_profile(width, height, False),
950 _gen_encoder_profile(width, height, True),
951 ])
952 elem.extend([
953 etree.Element('ImageEncoding', attrib={'quality': '90'}),
954 etree.Element('ImageEncoding', attrib={'quality': '80'}),
955 etree.Element('ImageEncoding', attrib={'quality': '70'}),
956 etree.Element('ImageDecoding', attrib={'memCap': '20000000'}),
957 ])
958 return elem
959
960 def _gen_encoder_profile(width, height, timelapse):
961 elem = etree.Element(
962 'EncoderProfile',
963 attrib={
964 'quality': ('timelapse' if timelapse else '') + str(height) + 'p',
965 'fileFormat': 'mp4',
966 'duration': '60',
967 })
968 elem.append(
969 etree.Element(
970 'Video',
971 attrib={
972 'codec': 'h264',
973 'bitRate': '8000000',
974 'width': str(width),
975 'height': str(height),
976 'frameRate': '30',
977 }))
978 elem.append(
979 etree.Element(
980 'Audio',
981 attrib={
982 'codec': 'aac',
983 'bitRate': '96000',
984 'sampleRate': '44100',
985 'channels': '1',
986 }))
987 return elem
988
989 def _gen_video_encoder_cap(name, min_bit_rate, max_bit_rate):
990 return etree.Element(
991 'VideoEncoderCap',
992 attrib={
993 'name': name,
994 'enabled': 'true',
995 'minBitRate': str(min_bit_rate),
996 'maxBitRate': str(max_bit_rate),
997 'minFrameWidth': '320',
998 'maxFrameWidth': '1920',
999 'minFrameHeight': '240',
1000 'maxFrameHeight': '1080',
1001 'minFrameRate': '15',
1002 'maxFrameRate': '30',
1003 })
1004
1005 def _gen_audio_encoder_cap(name, min_bit_rate, max_bit_rate, min_sample_rate,
1006 max_sample_rate):
1007 return etree.Element(
1008 'AudioEncoderCap',
1009 attrib={
1010 'name': name,
1011 'enabled': 'true',
1012 'minBitRate': str(min_bit_rate),
1013 'maxBitRate': str(max_bit_rate),
1014 'minSampleRate': str(min_sample_rate),
1015 'maxSampleRate': str(max_sample_rate),
1016 'minChannels': '1',
1017 'maxChannels': '1',
1018 })
1019
1020 camera_config = sw_config.camera_config
1021 if not camera_config.generate_media_profiles:
1022 return None
1023
1024 camera_pb = topology_pb2.HardwareFeatures.Camera
1025 root = etree.Element('MediaSettings')
1026 camera_id = 0
1027 for facing in [camera_pb.FACING_BACK, camera_pb.FACING_FRONT]:
1028 camera_device = next(
1029 (d for d in hw_features.camera.devices if d.facing == facing), None)
1030 if camera_device is None:
1031 continue
1032 if camera_config.camcorder_resolutions:
1033 resolutions = [
1034 (r.width, r.height) for r in camera_config.camcorder_resolutions
1035 ]
1036 else:
1037 resolutions = [(1280, 720)]
1038 if camera_device.flags & camera_pb.FLAGS_SUPPORT_1080P:
1039 resolutions.append((1920, 1080))
1040 root.append(_gen_camcorder_profiles(camera_id, resolutions))
1041 camera_id += 1
Ren-Pei Zengb55e4312020-11-18 17:03:01 +08001042 # media_profiles.xml should have at least one CamcorderProfiles.
1043 if camera_id == 0:
1044 return None
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001045
1046 root.extend([
1047 etree.Element('EncoderOutputFileFormat', attrib={'name': '3gp'}),
1048 etree.Element('EncoderOutputFileFormat', attrib={'name': 'mp4'}),
1049 _gen_video_encoder_cap('h264', 64000, 17000000),
1050 _gen_video_encoder_cap('h263', 64000, 1000000),
1051 _gen_video_encoder_cap('m4v', 64000, 2000000),
1052 _gen_audio_encoder_cap('aac', 758, 288000, 8000, 48000),
1053 _gen_audio_encoder_cap('heaac', 8000, 64000, 16000, 48000),
1054 _gen_audio_encoder_cap('aaceld', 16000, 192000, 16000, 48000),
1055 _gen_audio_encoder_cap('amrwb', 6600, 23050, 16000, 16000),
1056 _gen_audio_encoder_cap('amrnb', 5525, 12200, 8000, 8000),
1057 etree.Element(
1058 'VideoDecoderCap', attrib={
1059 'name': 'wmv',
1060 'enabled': 'false'
1061 }),
1062 etree.Element(
1063 'AudioDecoderCap', attrib={
1064 'name': 'wma',
1065 'enabled': 'false'
1066 }),
1067 ])
Ren-Pei Zeng21708cc2020-11-17 11:14:07 +08001068
1069 dtd_path = os.path.dirname(__file__)
1070 dtd = etree.DTD(os.path.join(dtd_path, 'media_profiles.dtd'))
1071 if not dtd.validate(root):
1072 raise etree.DTDValidateError(
1073 'Invalid media_profiles.xml generated:\n{}'.format(dtd.error_log))
1074
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001075 return XML_DECLARATION + etree.tostring(root, pretty_print=True)
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001076
1077
1078def _write_files_by_design_config(configs, output_dir, build_dir, system_dir,
1079 file_name_template, generate_file_content):
1080 """Writes generated files for each design config.
1081
1082 Args:
1083 configs: Source ConfigBundle to process.
1084 output_dir: Path to the generated output.
1085 build_dir: Path to the config file from portage's perspective.
1086 system_dir: Path to the config file in the target device.
1087 file_name_template: Template string of the config file name including one
1088 format()-style replacement field for the config id, e.g. 'config_{}.xml'.
1089 generate_file_content: Function to generate config file content from
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001090 HardwareFeatures and SoftwareConfig proto.
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001091 Returns:
1092 dict that maps the formatted config id to the correct file.
1093 """
1094 # pylint: disable=too-many-arguments,too-many-locals
C Shapiro5bf23a72020-04-24 11:40:17 -05001095 result = {}
C Shapiroea33cff2020-05-11 13:32:05 -05001096 configs_by_design = {}
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001097 for hw_design in configs.design_list:
C Shapiro5bf23a72020-04-24 11:40:17 -05001098 for design_config in hw_design.configs:
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001099 sw_config = _sw_config(configs.software_configs, design_config.id.value)
1100 config_content = generate_file_content(design_config.hardware_features,
1101 sw_config)
1102 if not config_content:
1103 continue
C Shapiroea33cff2020-05-11 13:32:05 -05001104 design_name = hw_design.name.lower()
C Shapiro5bf23a72020-04-24 11:40:17 -05001105
C Shapiroea33cff2020-05-11 13:32:05 -05001106 # Constructs the following map:
1107 # design_name -> config -> design_configs
1108 # This allows any of the following file naming schemes:
1109 # - All configs within a design share config (design_name prefix only)
1110 # - Nobody shares (full design_name and config id prefix needed)
1111 #
1112 # Having shared configs when possible makes code reviews easier around
1113 # the configs and makes debugging easier on the platform side.
C Shapiroea33cff2020-05-11 13:32:05 -05001114 arc_configs = configs_by_design.get(design_name, {})
1115 design_configs = arc_configs.get(config_content, [])
1116 design_configs.append(design_config)
1117 arc_configs[config_content] = design_configs
1118 configs_by_design[design_name] = arc_configs
C Shapiro9a3ac8c2020-04-25 07:49:21 -05001119
C Shapiroea33cff2020-05-11 13:32:05 -05001120 for design_name, unique_configs in configs_by_design.items():
1121 for file_content, design_configs in unique_configs.items():
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001122 file_name = file_name_template.format(design_name)
Andrew Lamb2413c982020-05-29 12:15:36 -06001123 if len(unique_configs) == 1:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001124 _write_file(output_dir, file_name, file_content)
C Shapiro9a3ac8c2020-04-25 07:49:21 -05001125
Andrew Lamb2413c982020-05-29 12:15:36 -06001126 for design_config in design_configs:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001127 config_id = _get_formatted_config_id(design_config)
Andrew Lamb2413c982020-05-29 12:15:36 -06001128 if len(unique_configs) > 1:
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001129 file_name = file_name_template.format(config_id)
1130 _write_file(output_dir, file_name, file_content)
1131 result[config_id] = _file_v2('{}/{}'.format(build_dir, file_name),
1132 '{}/{}'.format(system_dir, file_name))
C Shapiro5bf23a72020-04-24 11:40:17 -05001133 return result
1134
1135
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001136def _write_arc_hardware_feature_files(configs, output_root_dir, build_root_dir):
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001137 return _write_files_by_design_config(
1138 configs, output_root_dir + '/arc', build_root_dir + '/arc', '/etc',
1139 'hardware_features_{}.xml',
1140 lambda hw_features, _: _generate_arc_hardware_features(hw_features))
1141
1142
1143def _write_arc_media_profile_files(configs, output_root_dir, build_root_dir):
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001144 return _write_files_by_design_config(configs, output_root_dir + '/arc',
1145 build_root_dir + '/arc', '/etc',
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001146 'media_profiles_{}.xml',
1147 _generate_arc_media_profiles)
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001148
1149
Andrew Lambcd33f702020-06-11 10:45:16 -06001150def _read_config(path):
David Burgerd4f32962020-05-02 12:07:40 -06001151 """Reads a ConfigBundle proto from a json pb file.
David Burgere6f76222020-04-27 11:08:01 -06001152
1153 Args:
David Burgerd4f32962020-05-02 12:07:40 -06001154 path: Path to the file encoding the json pb proto.
David Burgere6f76222020-04-27 11:08:01 -06001155 """
1156 config = config_bundle_pb2.ConfigBundle()
1157 with open(path, 'r') as f:
1158 return json_format.Parse(f.read(), config)
1159
1160
Andrew Lambcd33f702020-06-11 10:45:16 -06001161def _merge_configs(configs):
David Burger7fd1dbe2020-03-26 09:26:55 -06001162 result = config_bundle_pb2.ConfigBundle()
1163 for config in configs:
1164 result.MergeFrom(config)
1165
1166 return result
1167
1168
David Burger1ba78a22020-06-18 18:42:47 -06001169def _camera_map(configs, project_name):
David Burger8ee9b4d2020-06-16 17:40:21 -06001170 """Produces a camera config map for the given configs.
1171
1172 Produces a map that maps from the design name to the camera config for that
1173 design.
1174
1175 Args:
1176 configs: Source ConfigBundle to process.
David Burger1ba78a22020-06-18 18:42:47 -06001177 project_name: Name of project processing for.
David Burger8ee9b4d2020-06-16 17:40:21 -06001178
1179 Returns:
1180 map from design name to camera config.
1181 """
1182 result = {}
Sean McAllisterf66887b2020-08-03 14:00:51 -06001183 for design in configs.design_list:
David Burger8ee9b4d2020-06-16 17:40:21 -06001184 design_name = design.name
David Burger0d9e8462020-06-19 14:12:37 -06001185 config_path = CAMERA_CONFIG_SOURCE_PATH_TEMPLATE.format(design_name.lower())
David Burger8ee9b4d2020-06-16 17:40:21 -06001186 if os.path.exists(config_path):
David Burger0d9e8462020-06-19 14:12:37 -06001187 destination = CAMERA_CONFIG_DEST_PATH_TEMPLATE.format(design_name.lower())
David Burger8ee9b4d2020-06-16 17:40:21 -06001188 result[design_name] = {
David Burger1ba78a22020-06-18 18:42:47 -06001189 'config-file':
1190 _file_v2(os.path.join(project_name, config_path), destination),
David Burger8ee9b4d2020-06-16 17:40:21 -06001191 }
1192 return result
1193
1194
David Burger52c9d322020-06-09 07:16:18 -06001195def _dptf_map(configs, project_name):
1196 """Produces a dptf map for the given configs.
1197
1198 Produces a map that maps from design name to the dptf file config for that
1199 design. It looks for the dptf files at:
David Burger2f0d9522020-07-30 10:52:28 -06001200 DPTF_PATH + '/' + DPTF_FILE
David Burger52c9d322020-06-09 07:16:18 -06001201 for a project wide config, that it maps under the empty string, and at:
David Burger2f0d9522020-07-30 10:52:28 -06001202 DPTF_PATH + '/' + design_name + '/' + DPTF_FILE
David Burger52c9d322020-06-09 07:16:18 -06001203 for design specific configs that it maps under the design name.
1204
1205 Args:
1206 configs: Source ConfigBundle to process.
1207 project_name: Name of project processing for.
1208
1209 Returns:
David Burger8ee9b4d2020-06-16 17:40:21 -06001210 map from design name or empty string (project wide), to dptf config.
David Burger52c9d322020-06-09 07:16:18 -06001211 """
1212 result = {}
David Burger52c9d322020-06-09 07:16:18 -06001213 # Looking at top level for project wide, and then for each design name
1214 # for design specific.
Sean McAllisterf66887b2020-08-03 14:00:51 -06001215 dirs = [""] + [d.name for d in configs.design_list]
David Burger52c9d322020-06-09 07:16:18 -06001216 for directory in dirs:
David Burgera2252762020-07-09 15:09:49 -06001217 design = directory.lower()
1218 if os.path.exists(os.path.join(DPTF_PATH, design, DPTF_FILE)):
David Burger2f0d9522020-07-30 10:52:28 -06001219 project_dptf_path = os.path.join(project_name, design, DPTF_FILE)
David Burger52c9d322020-06-09 07:16:18 -06001220 dptf_file = {
1221 'dptf-dv':
1222 project_dptf_path,
1223 'files': [
1224 _file(
David Burgera2252762020-07-09 15:09:49 -06001225 os.path.join(project_name, DPTF_PATH, design, DPTF_FILE),
David Burger52c9d322020-06-09 07:16:18 -06001226 os.path.join('/etc/dptf', project_dptf_path))
1227 ]
1228 }
1229 result[directory] = dptf_file
1230 return result
1231
1232
David Burgerceeb68a2020-09-03 11:31:10 -06001233def _wifi_sar_map(configs, project_name, output_dir, build_root_dir):
1234 """Constructs a map from design name to wifi sar config for that design.
1235
1236 Constructs a map from design name to the wifi sar config for that design.
1237 In the process a wifi sar hex file is generated that the config points at.
1238 This mapping is only made for the intel wifi where the generated file is
1239 provided when building coreboot.
1240
1241 Args:
1242 configs: Source ConfigBundle to process.
1243 project_name: Name of project processing for.
1244 output_dir: Path to the generated output.
Ren-Pei Zengc6ba15c2020-10-17 00:51:25 +08001245 build_root_dir: Path to the config file from portage's perspective.
David Burgerceeb68a2020-09-03 11:31:10 -06001246
1247 Returns:
1248 dict that maps the design name onto the wifi config for that design.
1249 """
1250 # pylint: disable=too-many-locals
1251 result = {}
1252 programs = {p.id.value: p for p in configs.program_list}
1253 sw_configs = list(configs.software_configs)
1254 for hw_design in configs.design_list:
1255 for hw_design_config in hw_design.configs:
1256 sw_config = _sw_config(sw_configs, hw_design_config.id.value)
1257 if sw_config.wifi_config.HasField('intel_config'):
1258 sar_file_content = _create_intel_sar_file_content(
1259 sw_config.wifi_config.intel_config)
1260 design_name = hw_design.name.lower()
1261 program = _lookup(hw_design.program_id, programs)
1262 wifi_sar_id = _extract_fw_config_value(hw_design_config, program,
1263 'Intel wifi sar id')
1264 output_path = os.path.join(output_dir, 'wifi')
1265 os.makedirs(output_path, exist_ok=True)
1266 filename = 'wifi_sar_{}.hex'.format(wifi_sar_id)
1267 output_path = os.path.join(output_path, filename)
1268 build_path = os.path.join(build_root_dir, 'wifi', filename)
1269 if os.path.exists(output_path):
1270 with open(output_path, 'r') as f:
1271 if f.read() != sar_file_content:
1272 raise Exception(
1273 'Project {} has conflicting wifi sar file content under '
1274 'wifi sar id {}.'.format(project_name, wifi_sar_id))
1275 else:
1276 with open(output_path, 'w') as f:
1277 f.write(sar_file_content)
1278 system_path = '/firmware/cbfs-rw-raw/{}/{}'.format(
1279 project_name, filename)
David Burger89e7cae2020-09-15 17:04:12 -06001280 result[design_name] = {'sar-file': _file_v2(build_path, system_path)}
David Burgerceeb68a2020-09-03 11:31:10 -06001281 return result
1282
1283
1284def _extract_fw_config_value(hw_design_config, program, name):
1285 """Extracts the firwmare config value with the given name.
1286
1287 Args:
1288 hw_design_config: Design extracting value from.
1289 program: Program the `hw_design_config` belongs to.
1290 name: Name of firmware config segment to extract.
1291
1292 Returns: the extracted value or raises a ValueError if no firmware
1293 configuration segment with `name` is found.
1294 """
1295 fw_config = hw_design_config.hardware_features.fw_config.value
1296 for fcs in program.firmware_configuration_segments:
1297 if fcs.name == name:
1298 value = fw_config & fcs.mask
1299 lsb_bit_set = (~fcs.mask + 1) & fcs.mask
1300 return value // lsb_bit_set
1301 raise ValueError(
1302 'No firmware configuration segment with name {} found'.format(name))
1303
1304
1305def _create_intel_sar_file_content(intel_config):
1306 """Creates and returns the intel sar file content for the given config.
1307
1308 Creates and returns the sar file content that is used with intel drivers
1309 only.
1310
1311 Args:
1312 intel_config: IntelConfig config.
1313
1314 Returns:
1315 sar file content for the given config, see:
1316 https://chromeos.google.com/partner/dlm/docs/connectivity/wifidyntxpower.html
1317 """
1318
1319 def to_hex(val):
1320 if val > 255 or val < 0:
1321 raise Exception('Sar file value %s out of range' % val)
1322 return '{0:0{1}X}'.format(val, 2)
1323
1324 def power_table(tpc):
1325 return (to_hex(tpc.limit_2g) + to_hex(tpc.limit_5g_1) +
1326 to_hex(tpc.limit_5g_2) + to_hex(tpc.limit_5g_3) +
1327 to_hex(tpc.limit_5g_4))
1328
1329 def wgds_value(wgds):
1330 return to_hex(wgds)
1331
1332 def offset_table(offsets):
1333 return (to_hex(offsets.max_2g) + to_hex(offsets.offset_2g_a) +
1334 to_hex(offsets.offset_2g_b) + to_hex(offsets.max_5g) +
1335 to_hex(offsets.offset_5g_a) + to_hex(offsets.offset_5g_b))
1336
1337 # See https://chromeos.google.com/partner/dlm/docs/connectivity/wifidyntxpower.html
1338 return (power_table(intel_config.tablet_mode_power_table_a) +
1339 power_table(intel_config.tablet_mode_power_table_b) +
1340 power_table(intel_config.non_tablet_mode_power_table_a) +
1341 power_table(intel_config.non_tablet_mode_power_table_b) +
1342 '00000000000000000000' + '00000000000000000000' +
1343 wgds_value(intel_config.wgds_version) +
1344 offset_table(intel_config.offset_fcc) +
1345 offset_table(intel_config.offset_eu) +
YH Lin89cddaa2021-03-08 08:31:47 -08001346 offset_table(intel_config.offset_other) + '\0')
David Burgerceeb68a2020-09-03 11:31:10 -06001347
1348
Andrew Lambcd33f702020-06-11 10:45:16 -06001349def Main(project_configs, program_config, output): # pylint: disable=invalid-name
David Burger7fd1dbe2020-03-26 09:26:55 -06001350 """Transforms source proto config into platform JSON.
1351
1352 Args:
1353 project_configs: List of source project configs to transform.
1354 program_config: Program config for the given set of projects.
1355 output: Output file that will be generated by the transform.
1356 """
Andrew Lambcd33f702020-06-11 10:45:16 -06001357 configs = _merge_configs([_read_config(program_config)] +
1358 [_read_config(config) for config in project_configs])
C Shapiro2b6d5332020-05-06 17:51:35 -05001359 touch_fw = {}
David Burger8ee9b4d2020-06-16 17:40:21 -06001360 camera_map = {}
David Burgerceeb68a2020-09-03 11:31:10 -06001361 dptf_map = {}
1362 wifi_sar_map = {}
C Shapiro5bf23a72020-04-24 11:40:17 -05001363 output_dir = os.path.dirname(output)
C Shapiro5c877992020-04-29 12:11:28 -05001364 build_root_dir = output_dir
C Shapiro5c877992020-04-29 12:11:28 -05001365 if 'sw_build_config' in output_dir:
1366 full_path = os.path.realpath(output)
Andrew Lamb6b607732020-08-24 15:52:46 -06001367 project_name = re.match(r'.*/(\w*)/(public_)?sw_build_config/.*',
Andrew Lamb2413c982020-05-29 12:15:36 -06001368 full_path).groups(1)[0]
C Shapiro5c877992020-04-29 12:11:28 -05001369 # Projects don't know about each other until they are integrated into the
1370 # build system. When this happens, the files need to be able to co-exist
1371 # without any collisions. This prefixes the project name (which is how
1372 # portage maps in the project), so project files co-exist and can be
1373 # installed together.
1374 # This is necessary to allow projects to share files at the program level
1375 # without having portage file installation collisions.
1376 build_root_dir = os.path.join(project_name, output_dir)
C Shapiro6830e6c2020-04-29 13:29:56 -05001377
David Burger1ba78a22020-06-18 18:42:47 -06001378 camera_map = _camera_map(configs, project_name)
David Burger52c9d322020-06-09 07:16:18 -06001379 dptf_map = _dptf_map(configs, project_name)
David Burgerceeb68a2020-09-03 11:31:10 -06001380 wifi_sar_map = _wifi_sar_map(configs, project_name, output_dir,
1381 build_root_dir)
David Burger52c9d322020-06-09 07:16:18 -06001382
C Shapiro2b6d5332020-05-06 17:51:35 -05001383 if os.path.exists(TOUCH_PATH):
Andrew Lambcd33f702020-06-11 10:45:16 -06001384 touch_fw = _build_touch_file_config(configs, project_name)
Andrew Lambcd33f702020-06-11 10:45:16 -06001385 arc_hw_feature_files = _write_arc_hardware_feature_files(
1386 configs, output_dir, build_root_dir)
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001387 arc_media_profile_files = _write_arc_media_profile_files(
1388 configs, output_dir, build_root_dir)
C Shapiro5bf23a72020-04-24 11:40:17 -05001389 config_files = ConfigFiles(
C Shapiro5bf23a72020-04-24 11:40:17 -05001390 arc_hw_features=arc_hw_feature_files,
Ren-Pei Zengacf03be2020-11-11 13:56:51 +08001391 arc_media_profiles=arc_media_profile_files,
C Shapiro2b6d5332020-05-06 17:51:35 -05001392 touch_fw=touch_fw,
David Burger8ee9b4d2020-06-16 17:40:21 -06001393 dptf_map=dptf_map,
David Burgerceeb68a2020-09-03 11:31:10 -06001394 camera_map=camera_map,
1395 wifi_sar_map=wifi_sar_map)
Andrew Lambcd33f702020-06-11 10:45:16 -06001396 write_output(_transform_build_configs(configs, config_files), output)
David Burger7fd1dbe2020-03-26 09:26:55 -06001397
1398
1399def main(argv=None):
1400 """Main program which parses args and runs
1401
1402 Args:
1403 argv: List of command line arguments, if None uses sys.argv.
1404 """
1405 if argv is None:
1406 argv = sys.argv[1:]
Andrew Lambcd33f702020-06-11 10:45:16 -06001407 opts = parse_args(argv)
David Burger7fd1dbe2020-03-26 09:26:55 -06001408 Main(opts.project_configs, opts.program_config, opts.output)
1409
1410
1411if __name__ == '__main__':
1412 sys.exit(main(sys.argv[1:]))