#!/usr/bin/env python3 # Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. import argparse import os import os.path import sys import tegra_pmx_soc_parser from tegra_pmx_utils import * dbg = False parser = argparse.ArgumentParser(description='Create a kernel pinctrl ' + 'driver from an SoC config file') parser.add_argument('--debug', action='store_true', help='Turn on debugging prints') parser.add_argument('soc', help='SoC to process') args = parser.parse_args() if args.debug: dbg = True if dbg: print(args) soc = tegra_pmx_soc_parser.load_soc(args.soc) print('''\ // SPDX-License-Identifier: GPL-2.0-only /* * Pinctrl data for the NVIDIA %s pinmux ''' % soc.titlename, end = '') if soc.kernel_author != 'NVIDIA': print(' *') print(' * Author: %s' % soc.kernel_author) print('''\ * * Copyright (c) %s, NVIDIA CORPORATION. All rights reserved. */ #include #include #include #include #include #include "pinctrl-tegra.h" /* * Most pins affected by the pinmux can also be GPIOs. Define these first. * These must match how the GPIO driver names/numbers its pins. */ ''' % soc.kernel_copyright_years, end='') # Do not add any more exceptions here; new SoCs should be formatted correctly if soc.name == 'tegra30': define_column = 41 else: define_column = 49 emit_define('_GPIO(offset)', '(offset)', define_column) print() last_gpio_define = None for gpio in soc.gpios_by_num(): emit_define(gpio.define, '_GPIO(%d)' % gpio.num, define_column) last_gpio_define = gpio.define print() print('/* All non-GPIO pins follow */') emit_define('NUM_GPIOS', '(%s + 1)' % last_gpio_define, define_column) emit_define('_PIN(offset)', '(NUM_GPIOS + (offset))', define_column) print() print('/* Non-GPIO pins */') for pin in soc.pins_by_num(): emit_define(pin.define, '_PIN(%d)' % pin.num, define_column) print() print('static const struct pinctrl_pin_desc %s_pins[] = {' % soc.name) for pin in soc.gpios_pins_by_num(): print('\tPINCTRL_PIN(%s, "%s"),' % (pin.define, pin.desc)) print('};') for pin in soc.gpios_pins_by_num(): if not pin.reg: continue print('''\ static const unsigned %s_pins[] = { %s, }; ''' % (pin.fullname, pin.define), end='') # Do not add any more exceptions here; new SoCs should be formatted correctly if soc.name == 'tegra30': f = soc.drive_groups_by_alpha else: f = soc.drive_groups_by_reg for group in f(): if group.has_matching_pin: continue print('''\ static const unsigned %s_pins[] = { ''' % group.fullname, end='') for pin in group.gpios_pins: print('\t%s,' % pin.define) print('};'); for group in soc.mipi_pad_ctrl_groups_by_reg(): print('''\ static const unsigned %s_pins[] = { ''' % group.fullname, end='') for pin in group.gpios_pins: print('\t%s,' % pin.define) print('};'); print('''\ enum tegra_mux { ''', end='') for func in soc.functions_by_alpha(): print('\tTEGRA_MUX_%s,' % func.name.upper()) print('''\ }; #define FUNCTION(fname) \\ { \\ .name = #fname, \\ } static struct tegra_function %s_functions[] = { ''' % soc.name, end='') for func in soc.functions_by_alpha(): print('\tFUNCTION(%s),' % func.name) drv_pingroup_val = "0x%x" % soc.soc_drv_reg_base print('''\ }; #define DRV_PINGROUP_REG_A %(drv_pingroup_val)s /* bank 0 */ #define PINGROUP_REG_A 0x3000 /* bank 1 */ ''' % globals(), end='') if len(soc.mipi_pad_ctrl_groups_by_reg()): print('#define MIPI_PAD_CTRL_PINGROUP_REG_A 0x820 /* bank 2 */''') print('''\ #define DRV_PINGROUP_REG(r) ((r) - DRV_PINGROUP_REG_A) #define PINGROUP_REG(r) ((r) - PINGROUP_REG_A) ''', end='') if len(soc.mipi_pad_ctrl_groups_by_reg()): print('''\ #define MIPI_PAD_CTRL_PINGROUP_REG_Y(r) ((r) - MIPI_PAD_CTRL_PINGROUP_REG_A) ''', end='') print('''\ #define PINGROUP_BIT_Y(b) (b) #define PINGROUP_BIT_N(b) (-1) ''', end='') params = ['pg_name', 'f0', 'f1', 'f2', 'f3', 'r'] if soc.soc_pins_have_od and not soc.soc_pins_all_have_od: params += ['od',] if soc.soc_pins_have_ior: params += ['ior',] if soc.soc_pins_have_rcv_sel: params += ['rcv_sel',] if soc.soc_pins_have_hsm: params += ['hsm',] if soc.soc_pins_have_schmitt and not soc.soc_pins_all_have_schmitt: params += ['schmitt',] if soc.soc_pins_have_drvtype: params += ['drvtype',] if soc.soc_pins_have_e_io_hv: params += ['e_io_hv',] drive_params = ['drvdn_b', 'drvdn_w', 'drvup_b', 'drvup_w', 'slwr_b', 'slwr_w', 'slwf_b', 'slwf_w'] if soc.soc_combine_pin_drvgroup: params += ['rdrv',] params += drive_params s = gen_wrapped_c_macro_header('PINGROUP', params) einput_val = str(soc.soc_einput_b) if soc.soc_pins_have_od: if soc.soc_pins_all_have_od: odrain_val = str(soc.soc_odrain_b) else: odrain_val = 'PINGROUP_BIT_##od(%s)' % str(soc.soc_odrain_b) else: odrain_val = '-1' if soc.soc_pins_have_ior: ioreset_val = 'PINGROUP_BIT_##ior(8)' else: ioreset_val = '-1' # rcv_sel and e_io_hv are different names for essentially the same thing. # Re-use the field to save space if soc.soc_pins_have_rcv_sel: rcv_sel_val = 'PINGROUP_BIT_##rcv_sel(9),' elif soc.soc_pins_have_e_io_hv: rcv_sel_val = 'PINGROUP_BIT_##e_io_hv(10),' else: rcv_sel_val = '-1,' s += '''\ { .name = #pg_name, .pins = pg_name##_pins, .npins = ARRAY_SIZE(pg_name##_pins), .funcs = { TEGRA_MUX_##f0, TEGRA_MUX_##f1, TEGRA_MUX_##f2, TEGRA_MUX_##f3, }, .mux_reg = PINGROUP_REG(r), .mux_bank = 1, .mux_bit = 0, .pupd_reg = PINGROUP_REG(r), .pupd_bank = 1, .pupd_bit = 2, .tri_reg = PINGROUP_REG(r), .tri_bank = 1, .tri_bit = 4, .einput_bit = %(einput_val)s, .odrain_bit = %(odrain_val)s, .lock_bit = 7, .ioreset_bit = %(ioreset_val)s, .rcv_sel_bit = %(rcv_sel_val)s ''' % globals() if soc.soc_pins_have_hsm: s += '''\ .hsm_bit = PINGROUP_BIT_##hsm(9), ''' if soc.soc_pins_have_schmitt: if soc.soc_pins_all_have_schmitt: s += '''\ .schmitt_bit = 12, ''' else: s += '''\ .schmitt_bit = PINGROUP_BIT_##schmitt(12), ''' if soc.soc_pins_have_drvtype: s += '''\ .drvtype_bit = PINGROUP_BIT_##drvtype(13), ''' if soc.soc_combine_pin_drvgroup: # FIXME: if !soc.soc_pins_have_hsm, then we should include hsm_bit # here. Same for schmitt and drvtype. However, no SoCs have that # combination at present, so I don't feel like cluttering the code. # We should also handle !soc_drvgroups_have_lpmd. s += '''\ .drv_reg = DRV_PINGROUP_REG(rdrv), .drv_bank = 0, .lpmd_bit = -1, .drvdn_bit = drvdn_b, .drvdn_width = drvdn_w, .drvup_bit = drvup_b, .drvup_width = drvup_w, .slwr_bit = slwr_b, .slwr_width = slwr_w, .slwf_bit = slwf_b, .slwf_width = slwf_w, ''' else: s += '''\ .drv_reg = -1, ''' if soc.soc_pins_all_have_parked: s += '''\ .parked_bitmask = BIT(%s), ''' % (soc.soc_parked_bit) else: s+= '''\ .parked_bitmask = 0, ''' s = append_aligned_tabs_indent_with_tabs(s, 72) print(s) print('''\ } ''', end='') params = ['pg_name', 'r'] if soc.soc_drvgroups_have_hsm: params += ['hsm_b',] if soc.soc_drvgroups_have_schmitt: params += ['schmitt_b',] if soc.soc_drvgroups_have_lpmd: params += ['lpmd_b',] if soc.soc_drvgroups_have_parked: params += ['prk_mask',] params += drive_params if soc.soc_drvgroups_have_drvtype: params += ['drvtype',] s = gen_wrapped_c_macro_header('DRV_PINGROUP', params) if soc.soc_drvgroups_have_hsm: hsm_bit_val = 'hsm_b' else: hsm_bit_val = '-1' if soc.soc_drvgroups_have_schmitt: schmitt_bit_val = 'schmitt_b' else: schmitt_bit_val = '-1' if soc.soc_drvgroups_have_lpmd: lpmd_bit_val = 'lpmd_b' else: lpmd_bit_val = '-1' if soc.soc_drvgroups_have_parked: parked_bit_mask = 'prk_mask' else: parked_bit_mask = '0' if soc.soc_drvgroups_have_drvtype: drvtype_bit_val = 'PINGROUP_BIT_##drvtype(6),' else: drvtype_bit_val = '-1,' s += '''\ { .name = "drive_" #pg_name, .pins = drive_##pg_name##_pins, .npins = ARRAY_SIZE(drive_##pg_name##_pins), .mux_reg = -1, .pupd_reg = -1, .tri_reg = -1, .einput_bit = -1, .odrain_bit = -1, .lock_bit = -1, .ioreset_bit = -1, .rcv_sel_bit = -1, .drv_reg = DRV_PINGROUP_REG(r), .drv_bank = 0, .hsm_bit = %(hsm_bit_val)s, .schmitt_bit = %(schmitt_bit_val)s, .lpmd_bit = %(lpmd_bit_val)s, .drvdn_bit = drvdn_b, .drvdn_width = drvdn_w, .drvup_bit = drvup_b, .drvup_width = drvup_w, .slwr_bit = slwr_b, .slwr_width = slwr_w, .slwf_bit = slwf_b, .slwf_width = slwf_w, .drvtype_bit = %(drvtype_bit_val)s .parked_bitmask = %(parked_bit_mask)s, ''' % globals() s = append_aligned_tabs_indent_with_tabs(s, 72) print(s) print('''\ } ''', end='') if len(soc.mipi_pad_ctrl_groups_by_reg()): print('''\ #define MIPI_PAD_CTRL_PINGROUP(pg_name, r, b, f0, f1) \\ { \\ .name = "mipi_pad_ctrl_" #pg_name, \\ .pins = mipi_pad_ctrl_##pg_name##_pins, \\ .npins = ARRAY_SIZE(mipi_pad_ctrl_##pg_name##_pins), \\ .funcs = { \\ TEGRA_MUX_ ## f0, \\ TEGRA_MUX_ ## f1, \\ TEGRA_MUX_RSVD3, \\ TEGRA_MUX_RSVD4, \\ }, \\ .mux_reg = MIPI_PAD_CTRL_PINGROUP_REG_Y(r), \\ .mux_bank = 2, \\ .mux_bit = b, \\ .pupd_reg = -1, \\ .tri_reg = -1, \\ .einput_bit = -1, \\ .odrain_bit = -1, \\ .lock_bit = -1, \\ .ioreset_bit = -1, \\ .rcv_sel_bit = -1, \\ .drv_reg = -1, \\ } ''', end='') print('''\ static const struct tegra_pingroup %s_groups[] = { ''' % soc.name, end='') # Do not add any more exceptions here; new SoCs should be formatted correctly if soc.name == 'tegra30': max_gpio_pin_len = max([len(pin.fullname) for pin in soc.gpios_pins_by_reg()]) max_f0_len = 12 max_f1_len = 12 max_f2_len = 12 max_f3_len = 12 yn_width = 1 col_widths = (max_gpio_pin_len, max_f0_len, max_f1_len, max_f2_len, max_f3_len, 6, yn_width, yn_width) if soc.soc_pins_have_rcv_sel: col_widths += (yn_width,) right_justifies = None elif soc.name in ('tegra114', 'tegra124'): max_gpio_pin_len = max([len(pin.fullname) for pin in soc.gpios_pins_by_reg()]) max_f0_len = 10 max_f1_len = 10 max_f2_len = 12 max_f3_len = 11 yn_width = 2 col_widths = (max_gpio_pin_len, max_f0_len, max_f1_len, max_f2_len, max_f3_len, 6, yn_width, yn_width) if soc.soc_pins_have_rcv_sel: col_widths += (yn_width,) right_justifies = (False, False, False, False, False, False, False, True, True, True) else: col_widths = None right_justifies = None headings = ['pg_name', 'f0', 'f1', 'f2', 'f3', 'r'] if soc.soc_pins_have_od and not soc.soc_pins_all_have_od: headings += ['od',] if soc.soc_pins_have_ior: headings += ['ior',] if soc.soc_pins_have_rcv_sel: headings += ['rcv_sel',] if soc.soc_pins_have_hsm: headings += ['hsm',] if soc.soc_pins_have_schmitt and not soc.soc_pins_all_have_schmitt: headings += ['schmitt',] if soc.soc_pins_have_drvtype: headings += ['drvtype',] if soc.soc_pins_have_e_io_hv: headings += ['e_io_hv',] if soc.soc_combine_pin_drvgroup: headings += ['rdrv',] headings += drive_params rows = [] # Do not add any more exceptions here; new SoCs should be formatted correctly if soc.name == 'tegra30': f = soc.gpios_pins_by_num else: f = soc.gpios_pins_by_reg for pin in f(): if not pin.reg: continue row = ( pin.fullname, pin.f0.upper(), pin.f1.upper(), pin.f2.upper(), pin.f3.upper(), '0x%x' % pin.reg, ) if soc.soc_pins_have_od and not soc.soc_pins_all_have_od: row += (boolean_to_yn(pin.od),) if soc.soc_pins_have_ior: row += (boolean_to_yn(pin.ior),) if soc.soc_pins_have_rcv_sel: row += (boolean_to_yn(pin.rcv_sel),) if soc.soc_pins_have_hsm: row += (boolean_to_yn(pin.hsm),) if soc.soc_pins_have_schmitt and not soc.soc_pins_all_have_schmitt: row += (boolean_to_yn(pin.schmitt),) if soc.soc_pins_have_drvtype: row += (boolean_to_yn(pin.drvtype),) if soc.soc_pins_have_e_io_hv: row += (boolean_to_yn(pin.e_io_hv),) if soc.soc_combine_pin_drvgroup: if pin.per_pin_drive_group: row += ( '0x%x' % pin.per_pin_drive_group.reg, repr(pin.per_pin_drive_group.drvdn_b), repr(pin.per_pin_drive_group.drvdn_w), repr(pin.per_pin_drive_group.drvup_b), repr(pin.per_pin_drive_group.drvup_w), repr(pin.per_pin_drive_group.slwr_b), repr(pin.per_pin_drive_group.slwr_w), repr(pin.per_pin_drive_group.slwf_b), repr(pin.per_pin_drive_group.slwf_w), ) else: row += ( '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', ) rows.append(row) dump_c_table(headings, 'PINGROUP', rows, col_widths=col_widths, right_justifies=right_justifies) # Do not add any more exceptions here; new SoCs should be formatted correctly if soc.name != 'tegra30': print() max_drvgrp_len = max([len(drvgroup.name) for drvgroup in soc.drive_groups_by_reg()]) print('\t/* pg_name, r, ', end='') if soc.soc_drvgroups_have_hsm: print('hsm_b, ', end='') if soc.soc_drvgroups_have_schmitt: print('schmitt_b, ', end='') if soc.soc_drvgroups_have_lpmd: print('lpmd_b, ', end='') if soc.soc_drvgroups_have_parked: print('prk_mask, ', end='') print('drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w', end='') if soc.soc_drvgroups_have_drvtype: print(', drvtype', end='') print(' */') rows = [] # Do not add any more exceptions here; new SoCs should be formatted correctly if soc.name == 'tegra30': f = soc.drive_groups_by_alpha else: f = soc.drive_groups_by_reg # Do not add any more exceptions here; new SoCs should be formatted correctly if soc.name in ('tegra30', 'tegra114', 'tegra124'): col_widths = (0, 0, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2) right_justifies = (False, False, True, True, True, True, True, True, True, True, True, True, True, True) else: col_widths = None right_justifies = None for drvgroup in f(): if drvgroup.has_matching_pin: continue row = ( drvgroup.name, '0x%x' % drvgroup.reg, ) if soc.soc_drvgroups_have_hsm: row += (repr(drvgroup.hsm_b),) if soc.soc_drvgroups_have_schmitt: row += (repr(drvgroup.schmitt_b),) if soc.soc_drvgroups_have_lpmd: row += (repr(drvgroup.lpmd_b),) if soc.soc_drvgroups_have_parked: if (drvgroup.prk_mask != -1): row += (hex(drvgroup.prk_mask),) else: row += (repr(drvgroup.prk_mask),) row += ( repr(drvgroup.drvdn_b), repr(drvgroup.drvdn_w), repr(drvgroup.drvup_b), repr(drvgroup.drvup_w), repr(drvgroup.slwr_b), repr(drvgroup.slwr_w), repr(drvgroup.slwf_b), repr(drvgroup.slwf_w), ) if soc.soc_drvgroups_have_drvtype: row += (boolean_to_yn(drvgroup.drvtype),) rows.append(row) dump_c_table(None, 'DRV_PINGROUP', rows, col_widths=col_widths, right_justifies=right_justifies) if len(soc.mipi_pad_ctrl_groups_by_reg()): print() headings = ('pg_name', 'r', 'b', 'f0', 'f1') rows = [] for group in soc.mipi_pad_ctrl_groups_by_reg(): row = ( group.name, '0x%x' % group.reg, repr(group.bit), group.f0.upper(), group.f1.upper(), ) rows.append(row) dump_c_table(headings, 'MIPI_PAD_CTRL_PINGROUP', rows ) socvars = { 'author': soc.kernel_author, 'soc': soc.name, 'usoc': soc.titlename, 'hsm_in_mux': boolean_to_c_bool(soc.soc_pins_have_hsm), 'schmitt_in_mux': boolean_to_c_bool(soc.soc_pins_have_schmitt), 'drvtype_in_mux': boolean_to_c_bool(soc.soc_pins_have_drvtype), } print('''\ }; static const struct tegra_pinctrl_soc_data %(soc)s_pinctrl = { .ngpios = NUM_GPIOS, .gpio_compatible = "nvidia,%(soc)s-gpio", .pins = %(soc)s_pins, .npins = ARRAY_SIZE(%(soc)s_pins), .functions = %(soc)s_functions, .nfunctions = ARRAY_SIZE(%(soc)s_functions), .groups = %(soc)s_groups, .ngroups = ARRAY_SIZE(%(soc)s_groups), .hsm_in_mux = %(hsm_in_mux)s, .schmitt_in_mux = %(schmitt_in_mux)s, .drvtype_in_mux = %(drvtype_in_mux)s, }; static int %(soc)s_pinctrl_probe(struct platform_device *pdev) { return tegra_pinctrl_probe(pdev, &%(soc)s_pinctrl); } static const struct of_device_id %(soc)s_pinctrl_of_match[] = { { .compatible = "nvidia,%(soc)s-pinmux", }, { }, }; static struct platform_driver %(soc)s_pinctrl_driver = { .driver = { .name = "%(soc)s-pinctrl", .of_match_table = %(soc)s_pinctrl_of_match, }, .probe = %(soc)s_pinctrl_probe, }; static int __init %(soc)s_pinctrl_init(void) { return platform_driver_register(&%(soc)s_pinctrl_driver); } arch_initcall(%(soc)s_pinctrl_init); ''' % socvars, end='')