Mainline:Broadcom Kona/Adding a new device: Difference between revisions
start writing draft |
|||
| (2 intermediate revisions by the same user not shown) | |||
| Line 20: | Line 20: | ||
'''The downstream Kona kernels used board files.''' (They did have some partial DT support, but it was never used for any production devices.) | '''The downstream Kona kernels used board files.''' (They did have some partial DT support, but it was never used for any production devices.) | ||
== | == Kernel compilation toolchain == | ||
( | To compile the kernel for the device, we will need a compiler toolchain for the ARM architecture. | ||
For convenience, we will use pmbootstrap (the postmarketOS build tool) with its envkernel.sh script, which handles toolchain setup automatically (everything is installed in a chroot managed by pmbootstrap, so no manual work needs to be done on the host system), and gives us the extra benefit of building a ready initramfs and rootfs image to boot with. | |||
=== mainline-tools setup === | |||
[https://uart.sh serialuart] uses a convenience script that wraps around envkernel.sh and automates the setup process and most commonly used commands: [https://github.com/refractionware/linux/tree/meta/mt mainline-tools]. | |||
This script sets up a couple of aliases, including: | |||
* <code>mb</code> (<code>mainline-build</code>) - shorthand for <code>make -j$(nproc)</code>, used to build the kernel. | |||
* <code>mp</code> (<code>mainline-package</code>) - creates a boot.img image for the built kernel. | |||
* <code>mf</code> (<code>mainline-flash</code>) - flashes the boot.img generated with <code>mp</code>. | |||
* <code>mbp</code> (<code>mainline-build-package</code>) - updates the postmarketOS kernel package (<code>linux-postmarketos-brcm-kona</code>) based on the build done with <code>mb</code>. | |||
* <code>msp</code> (<code>mainline-sideload-pkg</code>) - sideloads the latest kernel package (needed to update modules). | |||
{{note|A note about kernel packaging: | |||
* boot.img only contains the kernel and built-in drivers (Y in defconfig). | |||
* The kernel package (linux-postmarketos-brcm-kona) contains modules (M in defconfig). | |||
Flashing boot.img (<code>mp</code> and <code>mf</code>) will only update built-in modules; to update non-built-in modules on the device, use <code>mbp</code> and <code>msp</code> to sideload over USB (or regenerate the image with <code>pmbootstrap install</code>).}} | |||
To set up that script, run the following commands: | |||
<syntaxhighlight lang="shell-session"> | |||
$ mkdir ~/code | |||
$ cd ~/code | |||
$ git clone https://gitlab.postmarketos.org/postmarketOS/pmbootstrap # git clone is needed for envkernel.sh, even if you already have pmbootstrap installed | |||
$ wget https://raw.githubusercontent.com/refractionware/linux/refs/heads/meta/mt/mt.sh | |||
$ source ~/code/mt.sh | |||
</syntaxhighlight> | |||
When you start a session, run <code>source ~/code/mt.sh</code> to enable mainline-tools. | |||
== Getting the mainline kernel source == | |||
Broadcom Kona development happens in a close-to-mainline fork hosted on GitHub: [https://github.com/bcm-kona-mainline/linux bcm-kona-mainline/linux] | |||
Clone the kernel from GitHub: | |||
<syntaxhighlight lang="shell-session"> | |||
$ cd ~/code | |||
$ git clone https://github.com/bcm-kona-mainline/linux | |||
</syntaxhighlight> | |||
== Getting the downstream kernel source == | |||
You will need to reference the downstream kernel for your device for the porting process; most likely someone has uploaded it to GitHub (look for android_kernel_(vendor)_(codename) repos). | |||
Once you have the kernel downloaded, find the '''defconfig''' and '''board file''' for your device. | |||
* The defconfig is in <code>arch/arm/configs</code>; if you got a CyanogenMod/LineageOS kernel, look for a <code>cyanogenmod_XXX_defconfig</code>; otherwise, there should be a config with a name like <code>bcmXXXXX_codename_revXX_defconfig</code> (pick the highest revision number). | |||
* The board file is in <code>arch/arm/mach-PLATFORM/board-ss_CODENAME.c</code> (or just <code>board-CODENAME.c</code>), where PLATFORM is <code>capri</code> for BCM218xx, <code>rhea</code> for BCM21654, <code>hawaii</code> for BCM21664 and <code>java</code> for BCM23550. | |||
== Adding a device package in postmarketOS == | |||
Run <code>pmbootstrap init</code>. When asked for the device, provide the vendor and codename. | |||
* If you're asked to create a new device, follow the [https://wiki.postmarketos.org/wiki/Porting_to_a_new_device Porting Guide], using the <code>linux-postmarketos-brcm-kona</code> mainline kernel package. | |||
* If this ends up selecting an existing downstream/archived device, you'll need to update the device package - see [https://gitlab.postmarketos.org/postmarketOS/pmaports/-/merge_requests/8981/diffs?commit_id=fc2eb16282fe1b9dea7fb010533568899fad1bcb the commit doing this for samsung-baffinlite] as an example. | |||
== Adding a DTS for your device == | |||
The DTS describes the hardware of the device. DTS files for Broadcom-based devices are located in <code>arch/arm/boot/dts/broadcom</code>. | |||
{{hint|<code>[https://github.com/bcm-kona-mainline/linux/blob/kona/7.1/arch/arm/boot/dts/broadcom/bcm23550-samsung-baffinlite.dts bcm23550-samsung-baffinlite.dts]</code> is a good reference point for DTSes for all Kona chips.}} | |||
Create a new file in <code>arch/arm/boot/dts/broadcom</code> for your device with the filename <code>(soc)-(vendor)-(codename).dts</code> - for example, for a BCM21664 device with the codename samsung-kylepro, the filename will be <code>bcm21664-samsung-kylepro.dts</code>. Start from the following template (remove the comments when you're done): | |||
<syntaxhighlight lang="devicetree"> | |||
// SPDX-License-Identifier: GPL-2.0-only | |||
/* | |||
* Common device tree for Samsung Galaxy Trend Plus/S Duos 2 | |||
* (kylepro/kyleprods). | |||
* | |||
* Copyright (c) 2026 Your Name <youremail@example.com> | |||
*/ | |||
/dts-v1/; | |||
#include <dt-bindings/gpio/gpio.h> | |||
#include <dt-bindings/input/input.h> | |||
#include <dt-bindings/leds/common.h> | |||
// Depending on which SoC your device uses, change the following to: | |||
// BCM2166x - "bcm21664.dtsi" | |||
// BCM23550 - "bcm23550.dtsi" | |||
// BCM281x5 - "bcm11351.dtsi" | |||
#include "bcm21664.dtsi" | |||
/ { | |||
model = "Vendor Codename (MODEL-NUMBER)"; | |||
compatible = "vendor,codename", "brcm,bcm21664"; // remember to change the SoC compatible | |||
chassis-type = "handset"; // usually "handset" (smartphone) or "tablet" | |||
memory@80000000 { | |||
device_type = "memory"; | |||
reg = <0x80000000 0x30000000>; /* 768 MB; CHANGEME */ | |||
}; | |||
reserved-memory { | |||
#address-cells = <1>; | |||
#size-cells = <1>; | |||
ranges; | |||
coprocessor_mem: coprocessor-mem@80000000 { | |||
reg = <0x80000000 0x1e00000>; | |||
no-map; | |||
}; | |||
secure_mem: secure-mem@9d800000 { | |||
reg = <0x9d800000 0x100000>; | |||
no-map; | |||
}; | |||
mobicore: mobicore@9d900000 { | |||
reg = <0x9d900000 0x300000>; | |||
no-map; | |||
}; | |||
}; | |||
}; | |||
</syntaxhighlight> | |||
Then, open <code>arch/arm/boot/dts/broadcom/Makefile</code>, and locate the following section: | |||
<syntaxhighlight lang="makefile"> | |||
dtb-$(CONFIG_ARCH_BCM_MOBILE) += \ | |||
bcm28155-ap.dtb \ | |||
bcm21664-garnet.dtb \ | |||
bcm21664-samsung-kylepro.dtb \ | |||
bcm23550-samsung-baffinlite.dtb \ | |||
bcm23550-sparrow.dtb | |||
</syntaxhighlight> | |||
Add your DTS to the list, changing <code>.dts</code> to <code>.dtb</code>. | |||
=== Filling out the memory node === | |||
To get the memory size, as well as reserved regions, run the following command under a downstream kernel (e.g. under TWRP): | |||
<syntaxhighlight lang="shell-session"> | |||
$ cat /proc/iomem | |||
81e00000-afffffff : System RAM | |||
81e08000-823ec57b : Kernel code | |||
8251c000-826d72ff : Kernel data | |||
</syntaxhighlight> | |||
From the above, the RAM would begin at <code>81e00000</code> and have a size of <code>(0xafffffff+1) - 0x81e00000 = <b>0x2e200000</b></code>. | |||
{{todo|A lot of Samsung device kernels seem to be configured with a mem base of 0x81e00000, but in ATAG_MEM the 0x80000000 - 0x81e00000 chunk is also reported as a separate memory block as well. | |||
This memory region is likely used for storing coprocessor firmware blobs and communication with the modem and other coprocessors (see {{downstream|baffinlite|arch/arm/mach-java/include/mach/comms/platform_mconfig_hawaii.h}}). | |||
While from initial testing it seems safe to use with the modem disabled, I have included a <code>coprocessor_mem</code> block in the DTS snippet above to block out this region. | |||
TODO - figure out how to print ATAGs without serial. Typically they get printed over UART by the bootloader right before loading the kernel.}} | |||
=== UART === | |||
UART/serial is most notably used for sending debug logs over USB, but is also used for talking to the Bluetooth and GPS chip. | |||
Check the downstream board file; look for a struct of type <code>plat_serial8250_port</code>. It should look something like this: | |||
<syntaxhighlight lang="c"> | |||
static struct plat_serial8250_port hawaii_uart_platform_data[] = { | |||
HAWAII_8250PORT(UART0, UARTB_PERI_CLK_NAME_STR, 48000000, | |||
"bluetooth", NULL), | |||
HAWAII_8250PORT(UART1, UARTB2_PERI_CLK_NAME_STR, 26000000, | |||
"gps", &power_save_enable), | |||
HAWAII_8250PORT(UART2, UARTB3_PERI_CLK_NAME_STR, 26000000, | |||
"console", NULL), | |||
{ | |||
.flags = 0, | |||
}, | |||
} | |||
</syntaxhighlight> | |||
Note the numbers in the XXX_8250PORT macros; these represent the clock frequency. | |||
Also note the names given to the ports; there are a hint for what the ports are used for. As seen above, the layout is usually - uartb for Bluetooth, uartb2 for GPS and uartb3 for serial console. | |||
At the bottom of your DTS, add (change clock frequencies to match board file): | |||
<syntaxhighlight lang="devicetree"> | |||
&uartb { | |||
status = "okay"; | |||
clock-frequency = <48000000>; | |||
}; | |||
&uartb2 { | |||
status = "okay"; | |||
clock-frequency = <26000000>; | |||
}; | |||
&uartb3 { | |||
status = "okay"; | |||
clock-frequency = <26000000>; | |||
}; | |||
</syntaxhighlight> | |||
=== PMIC === | |||
Most Kona devices use BCM590xx series PMICs: BCM59054 for BCM21664/BCM23550, BCM59056 for BCM281xx and BCM59039 for BCM21654. The only known exceptions are the GT-I9150 (BCM281xx device with a BCM59054 and SMB358 for charging) and the GT-S6810 (Dialog DA2083). | |||
The PMIC is connected to a separate PMIC I2C bus (or BSC, as Broadcom calls their "I2C-compatible" bus): | |||
<syntaxhighlight lang="devicetree"> | |||
&pmu_bsc { | |||
clock-frequency = <3400000>; /* 3.2mhz? Downstream refers to this as a HS bus, but it doesn't give any speed information other than that. */ | |||
pinctrl-0 = <&pmbsc_pins>; | |||
pinctrl-names = "default"; | |||
status = "okay"; | |||
pmu: pmu@8 { | |||
compatible = "brcm,bcm59054"; | |||
reg = <0x08>; | |||
interrupt-parent = <&gpio>; | |||
interrupts = <29 IRQ_TYPE_EDGE_FALLING>; | |||
regulators { | |||
/* ... */ | |||
}; | |||
}; | |||
}; | |||
</syntaxhighlight> | |||
PMIC configuration is stored in a separate file in downstream, beginning with <code>board-bcm59xxx-(...).c</code> (same directory as the board file). Every regulator is described in this file, in <code>regulator_init_data</code> structs: | |||
<syntaxhighlight lang="c"> | |||
__weak struct regulator_consumer_supply rf_supply[] = { | |||
{.supply = "rf"}, | |||
}; | |||
static struct regulator_init_data bcm59xxx_rfldo_data = { | |||
.constraints = { | |||
.name = "rfldo", | |||
.min_uV = 1300000, | |||
.max_uV = 3300000, | |||
.valid_ops_mask = REGULATOR_CHANGE_STATUS | | |||
REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE, | |||
.valid_modes_mask = REGULATOR_MODE_NORMAL | | |||
REGULATOR_MODE_IDLE | | |||
REGULATOR_MODE_STANDBY, | |||
.always_on = 0, | |||
.initial_mode = REGULATOR_MODE_STANDBY, | |||
}, | |||
.num_consumer_supplies = ARRAY_SIZE(rf_supply), | |||
.consumer_supplies = rf_supply, | |||
}; | |||
</syntaxhighlight> | |||
Equivalent DTS fragment: | |||
<syntaxhighlight lang="devicetree"> | |||
rfldo_reg: rfldo { | |||
regulator-min-microvolt = <1300000>; | |||
regulator-max-microvolt = <3300000>; | |||
regulator-always-on; | |||
/* regulator-allowed-modes = <0x2 0x4 0x8>; */ /* NORMAL, IDLE, STANDBY */ | |||
/* regulator-initial-mode = <0x8>; */ /* REGULATOR_MODE_STANDBY */ | |||
}; | |||
</syntaxhighlight> | |||
Repeat for all regulator types; see DT bindings for reference ([https://github.com/bcm-kona-mainline/linux/blob/kona/7.1/Documentation/devicetree/bindings/regulator/brcm%2Cbcm59054.yaml BCM59054], [https://github.com/bcm-kona-mainline/linux/blob/kona/7.1/Documentation/devicetree/bindings/regulator/brcm%2Cbcm59056.yaml BCM59056]). | |||
=== SDIO/Storage === | |||
SDIO is used for internal storage, the SD card and WiFi. | |||
In the downstream board file, look for <code>sdio_platform_cfg</code> structs. Here's an example: | |||
<syntaxhighlight lang="c"> | |||
static struct sdio_platform_cfg hawaii_sdio_param[] = { | |||
{ | |||
.id = 0, | |||
.data_pullup = 0, | |||
.cd_gpio = SD_CARDDET_GPIO_PIN, | |||
.devtype = SDIO_DEV_TYPE_SDMMC, | |||
.flags = KONA_SDIO_FLAGS_DEVICE_REMOVABLE, | |||
.peri_clk_name = "sdio1_clk", | |||
.ahb_clk_name = "sdio1_ahb_clk", | |||
.sleep_clk_name = "sdio1_sleep_clk", | |||
.peri_clk_rate = 48000000, | |||
/*The SD card regulator*/ | |||
.vddo_regulator_name = "vdd_sdio", | |||
/*The SD controller regulator*/ | |||
.vddsdxc_regulator_name = "vdd_sdxc", | |||
.configure_sdio_pullup = configure_sdio_pullup, | |||
}, | |||
{ | |||
.id = 1, | |||
.data_pullup = 0, | |||
.is_8bit = 1, | |||
.devtype = SDIO_DEV_TYPE_EMMC, | |||
.flags = KONA_SDIO_FLAGS_DEVICE_NON_REMOVABLE , | |||
.peri_clk_name = "sdio2_clk", | |||
.ahb_clk_name = "sdio2_ahb_clk", | |||
.sleep_clk_name = "sdio2_sleep_clk", | |||
.peri_clk_rate = 52000000, | |||
}, | |||
{ | |||
.id = 2, | |||
.data_pullup = 0, | |||
.devtype = SDIO_DEV_TYPE_WIFI, | |||
.flags = KONA_SDIO_FLAGS_DEVICE_REMOVABLE, | |||
.peri_clk_name = "sdio3_clk", | |||
.ahb_clk_name = "sdio3_ahb_clk", | |||
.sleep_clk_name = "sdio3_sleep_clk", | |||
.peri_clk_rate = 48000000, | |||
#ifdef CONFIG_BRCM_UNIFIED_DHD_SUPPORT | |||
.wifi_gpio = { | |||
.reset = 3, | |||
.reg = -1, | |||
.host_wake = 74, | |||
.shutdown = -1, | |||
}, | |||
.register_status_notify = hawaii_wifi_status_register, | |||
#endif | |||
}, | |||
}; | |||
</syntaxhighlight> | |||
Things of note: | |||
* <code>.peri_clk_rate</code> is equivalent to <code>max-frequency</code> in DT; | |||
* <code>.is_8bit = 1</code> is equivalent to <code>bus-width = <8></code>; | |||
* <code>.cd_gpio</code> contains the card detect GPIO for the SD card slot. It is usually defined as a macro, the value is defined earlier in the board file. Here it's <code>91</code>. | |||
* <code>.vddo_regulator_name</code> and <code>.vddsdxc_regulator_name</code> become <code>vmmc-supply</code> and <code>vqmmc-supply</code> respectively. To find which regulator they are attached to, look up the names in your board file; you might find a struct like such: <syntaxhighlight lang="c">struct regulator_consumer_supply sd_supply[] = { | |||
{.supply = "sdldo_uc"}, | |||
REGULATOR_SUPPLY("vddmmc", "sdhci.3"), /* 0x3f1b0000.sdhci */ | |||
{.supply = "vdd_sdio"}, | |||
}; | |||
struct regulator_consumer_supply sdx_supply[] = { | |||
{.supply = "sdxldo_uc"}, | |||
REGULATOR_SUPPLY("vddo", "sdhci.3"), /* 0x3f1b0000.sdhci */ | |||
{.supply = "vdd_sdxc"}, | |||
};</syntaxhighlight> | |||
The first listed supply should show you the name of the BCM59xxx supply - in this case, <code>sdldo</code> and <code>sdxldo</code>. | |||
Equivalent mainline DTS: | |||
<syntaxhighlight lang="devicetree"> | |||
/* SD card */ | |||
&sdio1 { | |||
max-frequency = <48000000>; | |||
cd-gpios = <&gpio 91 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; | |||
vmmc-supply = <&sdldo_reg>; | |||
vqmmc-supply = <&sdxldo_reg>; | |||
/* NOTE: skip pinctrl here and in the other nodes for BCM28155, we don't have ready-made pinctrl definitions for it yet */ | |||
pinctrl-0 = <&sd_width4_pins>; | |||
pinctrl-names = "default"; | |||
status = "okay"; | |||
}; | |||
/* Internal storage */ | |||
&sdio2 { | |||
max-frequency = <52000000>; | |||
keep-power-in-suspend; | |||
non-removable; | |||
bus-width = <8>; | |||
pinctrl-0 = <&mmc0_width8_pins>; | |||
pinctrl-names = "default"; | |||
status = "okay"; | |||
}; | |||
/* WiFi */ | |||
&sdio3 { | |||
max-frequency = <48000000>; | |||
#address-cells = <1>; | |||
#size-cells = <0>; | |||
pinctrl-0 = <&mmc1_width4_pins>; | |||
pinctrl-names = "default"; | |||
// NOTE: Non-removable is hardcoded for the WiFi SDIO in the downstream driver, even if the board file claims it's removable. | |||
keep-power-in-suspend; | |||
non-removable; | |||
status = "okay"; | |||
}; | |||
</syntaxhighlight> | |||
=== I2C/BSC === | |||
Most sensors, as well as the touchscreen, are connected over I2C. Broadcom SoCs actually have an I2C-compatible bus called BSC. | |||
Finding exactly which sensors are used is a bit difficult, because board files tend to have data for a lot of sensors that is unused. You will need to look for sections guarded with <code>#ifdef CONFIG_...</code>; for the config option values, reference the downstream defconfig file for your device. | |||
In general, it's best to look through the defconfig first and find all the relevant options for sensors (look up keywords like SENSOR, PROXIMITY, ACCEL, MAG, LIGHT, TOUCH, INPUT...). | |||
(Alternatively, if you have a Samsung device, reference [https://docs.google.com/spreadsheets/d/1NioX9a2vgbEcO_Zs9COUFO-n3a2Rqf1JWWU1cfsktLM/edit?gid=0#gid=0 the spreadsheet].) | |||
In the board file, look for <code>i2c_board_info</code> structs: | |||
<syntaxhighlight lang="c"> | |||
#if defined(CONFIG_SENSORS_BMM050) | |||
#define BMA2X2_SLAVE_ADDR 0x10 | |||
#else | |||
#define BMA2X2_SLAVE_ADDR 0x18 | |||
#endif | |||
static struct i2c_board_info __initdata bsc3_i2c_boardinfo[] = | |||
{ | |||
#if defined(CONFIG_SENSORS_BMC150) | |||
#if defined(CONFIG_SENSORS_BMA2X2) | |||
{ | |||
I2C_BOARD_INFO("bma2x2", BMA2X2_SLAVE_ADDR), | |||
.platform_data = &bss_bma2x2, | |||
}, | |||
#endif | |||
#if defined(CONFIG_SENSORS_BMM050) | |||
{ | |||
I2C_BOARD_INFO("bmm050", 0x12), | |||
.platform_data = &bss_bmm050, | |||
}, | |||
#endif | |||
#endif | |||
#if defined (CONFIG_SENSORS_HSCDTD006A) || defined(CONFIG_SENSORS_HSCDTD008A) | |||
{ | |||
I2C_BOARD_INFO("hscd_i2c", 0x0c), | |||
.platform_data = &hscd_i2c_platform_data, | |||
}, | |||
#endif | |||
#if defined(CONFIG_SENSORS_GP2AP002) | |||
{ | |||
I2C_BOARD_INFO("gp2ap002",0x44), | |||
.platform_data = &gp2ap002_platform_data, | |||
} | |||
#endif | |||
} | |||
</syntaxhighlight> | |||
Do a <code>grep -iR</code> with the codename in <code>drivers</code> in mainline to see if you can spot a driver for the sensor you want to add. Many sensors from that era are already supported in mainline. You can look at other device trees (<code>arch/arm/boot/dts</code> and <code>arch/arm64/boot/dts</code>) as well as DT bindings (<code>Documentation/devicetree/bindings</code>) to figure out how to add them to your DTS. | |||
For the exact values to use in DT, you'll have to look at the <code>platform_data</code> struct, and sometimes at the driver for the peripheral (which you can usually find by grepping the downstream source code for the model number/driver name). | |||
<syntaxhighlight lang="devicetree"> | |||
&bsc3 { | |||
clock-frequency = <400000>; | |||
// NOTE: again, pinctrl only applies to BCM21664/BCM23550 at the moment | |||
pinctrl-0 = <&bsc3_pins>; | |||
pinctrl-names = "default"; | |||
status = "okay"; | |||
magnetometer@c { | |||
compatible = "alps,hscdtd008a"; | |||
reg = <0x0c>; | |||
}; | |||
accel@18 { | |||
compatible = "bosch,bma254"; | |||
reg = <0x18>; | |||
/* ... */ | |||
}; | |||
proximity@44 { | |||
compatible = "sharp,gp2ap002s00f"; | |||
reg = <0x44>; | |||
/* ... */ | |||
}; | |||
}; | |||
</syntaxhighlight> | |||
=== USB === | |||
USB comprises of 3 parts: | |||
* The USB OTG controller (usbotg node); | |||
* The USB PHY (usbphy node); | |||
* The USB mode switch (not all devices - BCM59039 devices don't seem to be paired with a switch). | |||
Commonly used switches include the FSA9480/9485, TSUxxxx and RTxxxx. Look them up in your defconfig (keywords: FSA, TSU, RT). | |||
On Samsung devices, the switches are often connected over I2C-GPIO (which is an I2C bus bitbanged over GPIO pins). Example from baffinlite: | |||
<syntaxhighlight lang="c"> | |||
#define GPIO_FSA9485_I2C_SDA 113 | |||
#define GPIO_FSA9485_I2C_SCL 114 | |||
#define GPIO_FSA9485_INT 56 | |||
/* ... */ | |||
static struct i2c_board_info __initdata micro_usb_i2c_devices_info[] = { | |||
{ | |||
I2C_BOARD_INFO("fsa9485", 0x4A >> 1), | |||
.platform_data = &fsa9485_pdata, | |||
.irq = gpio_to_irq(GPIO_FSA9485_INT), | |||
}, | |||
}; | |||
static struct i2c_gpio_platform_data fsa_i2c_gpio_data={ | |||
.sda_pin = GPIO_FSA9485_I2C_SDA, | |||
.scl_pin = GPIO_FSA9485_I2C_SCL, | |||
.udelay = 2, | |||
}; | |||
</syntaxhighlight> | |||
Note - <code>0x4A >> 1</code> means a bit shift, you can paste it into the Python interpreter and it will give you the value (<code>hex(0x4A >> 1)</code> gives <code>0x25</code>). | |||
In mainline, this becomes: | |||
<syntaxhighlight lang="devicetree"> | |||
/ { | |||
/* (add this under the / node ) */ | |||
/* ... */ | |||
/* USB switch */ | |||
i2c-musb { | |||
#address-cells = <1>; | |||
#size-cells = <0>; | |||
compatible = "i2c-gpio"; | |||
sda-gpios = <&gpio 113 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; | |||
scl-gpios = <&gpio 114 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; | |||
i2c-gpio,delay-us = <2>; | |||
musb@25 { | |||
compatible = "fcs,fsa9480"; | |||
reg = <0x25>; | |||
interrupt-parent = <&gpio>; | |||
interrupts = <56 IRQ_TYPE_LEVEL_HIGH>; | |||
connector { | |||
compatible = "samsung,usb-connector-11pin", | |||
"usb-b-connector"; | |||
label = "micro-USB"; | |||
type = "micro"; | |||
ports { | |||
#address-cells = <1>; | |||
#size-cells = <0>; | |||
port@0 { | |||
reg = <0>; | |||
muic_to_usb: endpoint { | |||
remote-endpoint = <&usb_to_muic>; | |||
}; | |||
}; | |||
}; | |||
}; | |||
}; | |||
}; | |||
/* ... */ | |||
}; | |||
</syntaxhighlight> | |||
Once you have the switch, you can add the remaining USB nodes: | |||
<syntaxhighlight lang="devicetree"> | |||
&usbotg { | |||
vusb_d-supply = <&usbldo_reg>; | |||
vusb_a-supply = <&iosr1_reg>; | |||
vbus-supply = <&vbus_reg>; | |||
dr_mode = "otg"; | |||
role-switch-default-mode = "peripheral"; | |||
usb-role-switch; | |||
status = "okay"; | |||
// if your device has no switch, drop the port node below | |||
port { | |||
usb_to_muic: endpoint { | |||
remote-endpoint = <&muic_to_usb>; | |||
}; | |||
}; | |||
}; | |||
&usbphy { | |||
status = "okay"; | |||
}; | |||
</syntaxhighlight> | |||
=== WiFi and Bluetooth === | |||
Most Broadcom devices use Broadcom WiFi/Bluetooth chips from the BCM43xx series. (Look up BCM43 in your defconfig, or reference downstream kernel dmesg for the exact model.) | |||
The below examples are for BCM4330. If you have another chip, you can grep for it in the mainline kernel (<code>arch/arm/boot/dts</code>) and see what compatibles are used by other devices. | |||
The Bluetooth chip goes under the UART bus that was labeled as "bluetooth": | |||
<syntaxhighlight lang="devicetree"> | |||
&uartb { | |||
status = "okay"; | |||
clock-frequency = <48000000>; | |||
bluetooth { | |||
compatible = "brcm,bcm4330-bt"; | |||
shutdown-gpios = <&gpio 28 GPIO_ACTIVE_HIGH>; | |||
device-wakeup-gpios = <&gpio 32 GPIO_ACTIVE_HIGH>; | |||
host-wakeup-gpios = <&gpio 72 GPIO_ACTIVE_HIGH>; | |||
reset-gpios = <&gpio 71 GPIO_ACTIVE_LOW>; | |||
interrupt-parent = <&gpio>; | |||
interrupts = <72 IRQ_TYPE_EDGE_FALLING>; | |||
}; | |||
}; | |||
</syntaxhighlight> | |||
To get the GPIOs: | |||
* Look for <code>bcmbt_platform_data</code>; <code>.bt_wake_gpio</code> becomes <code>device-wakeup-gpios</code>, and <code>.host_wake_gpio</code> becomes <code>host-wakeup-gpios</code>. | |||
* Look for <code>bcmbt_rfkill_platform_data</code>; <code>.vreg_gpio</code> becomes <code>shutdown-gpios</code>, and <code>.n_reset_gpio</code> becomes <code>reset-gpios</code>. | |||
For WiFi, add the following under the <code>/</code> node: | |||
<syntaxhighlight lang="devicetree"> | |||
/ { | |||
/* ... */ | |||
/* GPIO regulator for WiFi */ | |||
wl_reg: regulator-gpio-wlan { | |||
compatible = "regulator-fixed"; | |||
regulator-name = "WL_REG_ON"; | |||
regulator-min-microvolt = <3000000>; | |||
regulator-max-microvolt = <3000000>; | |||
startup-delay-us = <100000>; | |||
gpio = <&gpio 3 GPIO_ACTIVE_HIGH>; | |||
enable-active-high; | |||
}; | |||
/* ... */ | |||
}; | |||
</syntaxhighlight> | |||
(Get the GPIO from <code>board_wifi_info</code>, member <code>.wl_reset_gpio</code>). | |||
Then, update the SDIO node for WiFi: | |||
<syntaxhighlight lang="devicetree"> | |||
/* WiFi */ | |||
&sdio3 { | |||
max-frequency = <48000000>; | |||
/* Actually a regulator for the WiFi chip */ | |||
vmmc-supply = <&wl_reg>; | |||
#address-cells = <1>; | |||
#size-cells = <0>; | |||
pinctrl-0 = <&mmc1_width4_pins>; | |||
pinctrl-names = "default"; | |||
keep-power-in-suspend; | |||
non-removable; | |||
status = "okay"; | |||
wifi@1 { | |||
compatible = "brcm,bcm4330-fmac", "brcm,bcm4329-fmac"; | |||
reg = <1>; | |||
interrupt-parent = <&gpio>; | |||
interrupts = <74 IRQ_TYPE_EDGE_FALLING>; | |||
interrupt-names = "host-wake"; | |||
}; | |||
}; | |||
</syntaxhighlight> | |||
(Get the interrupt from <code>board_wifi_info</code>, member <code>.host_wake_gpio</code>). | |||
=== GPIO keys === | |||
Many Samsung devices use GPIO-based keys for the volume up/down and home keys. (The power button is handled by the PMIC, and the touchkeys (menu/back next to home button) are usually handled by the touchscreen). | |||
<syntaxhighlight lang="c"> | |||
#define GPIO_KEYS_SETTINGS { \ | |||
{ KEY_VOLUMEUP,9, 1, "VOLUMEUP", EV_KEY, 0, 64}, \ | |||
{ KEY_HOME, 10, 1, "HOME", EV_KEY, 0, 64}, \ | |||
{ KEY_VOLUMEDOWN,11, 1, "VOLUMEDOWN", EV_KEY, 0, 64}, \ | |||
} | |||
#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) | |||
static struct gpio_keys_button board_gpio_keys[] = GPIO_KEYS_SETTINGS; | |||
/* ... */ | |||
#endif | |||
</syntaxhighlight> | |||
Equivalent DT fragment: | |||
<syntaxhighlight lang="devicetree"> | |||
/ { | |||
/* ... */ | |||
/* Buttons */ | |||
gpio-keys { | |||
compatible = "gpio-keys"; | |||
key-volume-up { | |||
label = "Volume Up"; | |||
gpios = <&gpio 9 GPIO_ACTIVE_LOW>; | |||
linux,code = <KEY_VOLUMEUP>; | |||
}; | |||
key-home { | |||
label = "Home"; | |||
gpios = <&gpio 10 GPIO_ACTIVE_LOW>; | |||
linux,code = <KEY_HOMEPAGE>; | |||
}; | |||
key-volume-down { | |||
label = "Volume Down"; | |||
gpios = <&gpio 11 GPIO_ACTIVE_LOW>; | |||
linux,code = <KEY_VOLUMEDOWN>; | |||
}; | |||
}; | |||
/* ... */ | |||
}; | |||
</syntaxhighlight> | |||
=== Keypad === | |||
{{note|Keypad is only added for BCM21664/BCM23550 at the moment; it's most likely the same for BCM28155, just a matter of adding the right node like [https://github.com/bcm-kona-mainline/linux/commit/86a15664bdfe457bcd994b2ae72f722509259b53 in the equivalent bcm21664-common.dtsi commit].}} | |||
Some devices use the built-in keypad peripheral for volume up/down keys. If you have <code>CONFIG_KEYBOARD_BCM</code> enabled in downstream defconfig, look for <code>bcm_keymap</code> in your board file: | |||
<syntaxhighlight lang="c"> | |||
#ifdef CONFIG_KEYBOARD_BCM | |||
static struct bcm_keymap hawaii_keymap[] = { | |||
{BCM_KEY_ROW_0, BCM_KEY_COL_0, "unused", 0}, | |||
{BCM_KEY_ROW_0, BCM_KEY_COL_1, "Vol Down Key", KEY_VOLUMEDOWN}, | |||
{BCM_KEY_ROW_0, BCM_KEY_COL_2, "unused", 0}, | |||
{BCM_KEY_ROW_0, BCM_KEY_COL_3, "Vol Up Key", KEY_VOLUMEUP}, | |||
{BCM_KEY_ROW_0, BCM_KEY_COL_4, "unused", 0}, | |||
{BCM_KEY_ROW_0, BCM_KEY_COL_5, "unused", 0}, | |||
/* ... */ | |||
}; | |||
static struct bcm_keypad_platform_info hawaii_keypad_data = { | |||
.row_num = 1, | |||
.col_num = 5, | |||
.keymap = hawaii_keymap, | |||
.bcm_keypad_base = (void *)__iomem HW_IO_PHYS_TO_VIRT(KEYPAD_BASE_ADDR), | |||
}; | |||
#endif | |||
</syntaxhighlight> | |||
Equivalent DTS: | |||
<syntaxhighlight lang="devicetree"> | |||
&keypad { | |||
keypad,num-rows = <1>; | |||
keypad,num-columns = <5>; | |||
linux,keymap = <MATRIX_KEY(0x00, 0x01, KEY_VOLUMEDOWN)>, | |||
<MATRIX_KEY(0x00, 0x03, KEY_VOLUMEUP)>; | |||
status = "okay"; | |||
}; | |||
</syntaxhighlight> | |||
== Building the kernel == | |||
To apply the pmOS Broadcom Kona defconfig: | |||
<syntaxhighlight lang="shell-session"> | |||
$ make bcmkona_pmos_defconfig | |||
</syntaxhighlight> | |||
To build the kernel: | |||
<syntaxhighlight lang="shell-session"> | |||
$ make -j$(nproc) | |||
-- or, with mainline-tools: -- | |||
$ mb | |||
</syntaxhighlight> | |||
If you have mainline-tools, you can flash the kernel with: | |||
<syntaxhighlight lang="shell-session"> | |||
$ mp | |||
$ mf | |||
</syntaxhighlight> | |||