Index: head/share/man/man4/man4.aarch64/rk_gpio.4 =================================================================== --- head/share/man/man4/man4.aarch64/rk_gpio.4 (revision 355356) +++ head/share/man/man4/man4.aarch64/rk_gpio.4 (revision 355357) @@ -1,63 +1,62 @@ .\"- .\" Copyright (c) 2018 Emmanuel Vadot -.\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd Apr 26, 2018 .Dt RK_GPIO 4 .Os .Sh NAME .Nm rk_gpio .Nd driver for the gpio controller on RockChip SoCs .Sh SYNOPSIS .Cd "options SOC_ROCKCHIP_RK3328" .Sh DESCRIPTION The .Nm device driver provides support for the gpio controller device present on RockChip SoC. .Sh HARDWARE The current version of the .Nm driver supports the gpio banks with one of the following compatible strings : .Pp .Bl -bullet -compact .It rockchip,gpio-bank .El .Sh SEE ALSO .Xr gpiobus 4 , .Xr gpioctl 8 , .Sh HISTORY The .Nm device driver first appeared in .Fx 12.0 . .Sh AUTHORS The .Nm device driver and manpage was written by .An Emmanuel Vadot Aq Mt manu@freebsd.org . Index: head/share/man/man4/man4.aarch64/rk_grf.4 =================================================================== --- head/share/man/man4/man4.aarch64/rk_grf.4 (revision 355356) +++ head/share/man/man4/man4.aarch64/rk_grf.4 (revision 355357) @@ -1,60 +1,59 @@ .\"- .\" Copyright (c) 2018 Emmanuel Vadot -.\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd Apr 26, 2018 .Dt RK_GRF 4 .Os .Sh NAME .Nm rk_grf .Nd driver for the General Register Files controller on RockChip SoCs .Sh SYNOPSIS .Cd "options SOC_ROCKCHIP_rk3328" .Sh DESCRIPTION The .Nm device driver provides support for the RockChip General Register Files system controller. .Sh HARDWARE The current version of the .Nm driver supports the GRF controller with one of the following compatible strings : .Pp .Bl -bullet -compact .It rockchip,rk3328-grf .El .Sh HISTORY The .Nm device driver first appeared in .Fx 12.0 . .Sh AUTHORS The .Nm device driver and manpage was written by .An Emmanuel Vadot Aq Mt manu@freebsd.org . Index: head/share/man/man4/man4.aarch64/rk_pinctrl.4 =================================================================== --- head/share/man/man4/man4.aarch64/rk_pinctrl.4 (revision 355356) +++ head/share/man/man4/man4.aarch64/rk_pinctrl.4 (revision 355357) @@ -1,62 +1,61 @@ .\"- .\" Copyright (c) 2018 Emmanuel Vadot -.\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd Apr 26, 2018 .Dt RK_PINCTRL 4 .Os .Sh NAME .Nm rk_pinctrl .Nd driver for the pin multiplexing on RockChip SoCs .Sh SYNOPSIS .Cd "options SOC_ROCKCHIP_RK3328" .Sh DESCRIPTION The .Nm device driver provides support for the pin multiplexing device present on RockChip SoC. .Sh HARDWARE The current version of the .Nm driver supports the pin controller with one of the following compatible strings : .Pp .Bl -bullet -compact .It rockchip,rk3328-pinctrl .El .Sh SEE ALSO .Xr fdt_pinctrl 4 , .Sh HISTORY The .Nm device driver first appeared in .Fx 12.0 . .Sh AUTHORS The .Nm device driver and manpage was written by .An Emmanuel Vadot Aq Mt manu@freebsd.org . Index: head/share/man/man4/man4.arm/aw_gpio.4 =================================================================== --- head/share/man/man4/man4.arm/aw_gpio.4 (revision 355356) +++ head/share/man/man4/man4.arm/aw_gpio.4 (revision 355357) @@ -1,102 +1,101 @@ .\"- .\" Copyright (c) 2017 Emmanuel Vadot -.\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd Dec 25, 2017 .Dt AW_GPIO 4 .Os .Sh NAME .Nm aw_gpio .Nd driver for the GPIO and pin muxing functionalities on Allwinner SoC .Sh SYNOPSIS .Cd "device gpio" .Cd "options SOC_ALLWINNER_A10" .Cd "options SOC_ALLWINNER_A13" .Cd "options SOC_ALLWINNER_A20" .Cd "options SOC_ALLWINNER_A31" .Cd "options SOC_ALLWINNER_A31S" .Cd "options SOC_ALLWINNER_A33" .Cd "options SOC_ALLWINNER_A83T" .Cd "options SOC_ALLWINNER_H2PLUS" .Cd "options SOC_ALLWINNER_H3" .Cd "options SOC_ALLWINNER_A64" .Cd "options SOC_ALLWINNER_H5" .Sh DESCRIPTION The .Nm device driver provides support for the Allwinner pin muxing and GPIO on Allwinner SoCs. .Sh HARDWARE The current version of the .Nm driver supports the GPIO/pinmuxing controller with one of the following compatible strings : .Pp .Bl -bullet -compact .It allwinner,sun4i-a10-pinctrl .It allwinner,sun5i-a13-pinctrl .It allwinner,sun7i-a20-pinctrl .It allwinner,sun6i-a31-pinctrl .It allwinner,sun6i-a31s-pinctrl .It allwinner,sun6i-a31-r-pinctrl .It allwinner,sun6i-a33-pinctrl .It allwinner,sun8i-a83t-pinctrl .It allwinner,sun8i-a83t-r-pinctrl .It allwinner,sun8i-h3-pinctrl .It allwinner,sun50i-h5-pinctrl .It allwinner,sun8i-h3-r-pinctrl .It allwinner,sun50i-a64-pinctrl .It allwinner,sun50i-a64-r-pinctrl .El .Sh SEE ALSO .Xr fdt 4 , .Xr gpio 4 .Sh HISTORY The .Nm device driver first appeared in .Fx 10.0 . .Sh AUTHORS The .Nm device driver was originally written by .An Ganbold Tsagaankhuu Aq Mt ganbold@freebsd.org . This manual page was written by .An Emmanuel Vadot Aq Mt manu@freebsd.org . Index: head/share/man/man4/man4.arm/aw_mmc.4 =================================================================== --- head/share/man/man4/man4.arm/aw_mmc.4 (revision 355356) +++ head/share/man/man4/man4.arm/aw_mmc.4 (revision 355357) @@ -1,76 +1,75 @@ .\"- .\" Copyright (c) 2017 Emmanuel Vadot -.\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd Dec 25, 2017 .Dt AW_MMC 4 .Os .Sh NAME .Nm aw_mmc .Nd driver for the SD/MMC controller in Allwinner SoC .Sh SYNOPSIS .Cd "device mmc" .Sh DESCRIPTION The .Nm device driver provides support for the Allwinner SD/MMC host controller. .Sh HARDWARE The current version of the .Nm driver supports the SD/MMC controller with one of the following compatible strings : .Pp .Bl -bullet -compact .It allwinner,sun4i-a10-mmc .It allwinner,sun5i-a13-mmc .It allwinner,sun7i-a20-mmc .It allwinner,sun50i-a64-mmc .El .Sh SYSCTL VARIABLES The following read-only variables are available via .Xr sysctl 8 : .Bl -tag -width indent .It Va dev.aw_mmc.req_timeout Request timeout in seconds (default: 10) . .El .Sh SEE ALSO .Xr fdt 4 , .Xr mmc 4 .Sh HISTORY The .Nm device driver first appeared in .Fx 10.0 . .Sh AUTHORS The .Nm device driver was originally written by .An Alexander Fedorov Aq Mt alexander.fedorov@rtlservice.com . Later work and this manual page was done by .An Emmanuel Vadot Aq Mt manu@freebsd.org . Index: head/share/man/man4/man4.arm/aw_rtc.4 =================================================================== --- head/share/man/man4/man4.arm/aw_rtc.4 (revision 355356) +++ head/share/man/man4/man4.arm/aw_rtc.4 (revision 355357) @@ -1,63 +1,62 @@ .\"- .\" Copyright (c) 2017 Emmanuel Vadot -.\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd Dec 25, 2017 .Dt AW_RTC 4 .Os .Sh NAME .Nm aw_rtc .Nd driver for the RTC controller in Allwinner SoC .Sh DESCRIPTION The .Nm device driver provides support for the Allwinner RTC controller. .Sh HARDWARE The current version of the .Nm driver supports the RTC controller with one of the following compatible strings : .Pp .Bl -bullet -compact .It allwinner,sun4i-a10-rtc .It allwinner,sun7i-a20-rtc .It allwinner,sun6i-a31-rtc .El .Sh HISTORY The .Nm device driver first appeared in .Fx 11.0 . .Sh AUTHORS The .Nm device driver was written by .An Vladimir Belian Aq Mt fate10@gmail.com . This manual page was written by .An Emmanuel Vadot Aq Mt manu@freebsd.org . Index: head/share/man/man4/man4.arm/aw_spi.4 =================================================================== --- head/share/man/man4/man4.arm/aw_spi.4 (revision 355356) +++ head/share/man/man4/man4.arm/aw_spi.4 (revision 355357) @@ -1,58 +1,57 @@ .\"- .\" Copyright (c) 2018 Emmanuel Vadot -.\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd May 17, 2018 .Dt AW_SPI 4 .Os .Sh NAME .Nm aw_spi .Nd driver for the SPI controller in Allwinner SoC .Sh SYNOPSIS .Cd "device aw_spi" .Sh DESCRIPTION The .Nm device driver provides support for the Allwinner SPI host controller. .Sh HARDWARE The current version of the .Nm driver supports the SPI controller with one of the following compatible strings: .Pp .Bl -bullet -compact .It allwinner,sun8i-h3-spi .El .Sh HISTORY The .Nm device driver first appeared in .Fx 12.0 . .Sh AUTHORS The .Nm device driver was written by .An Emmanuel Vadot Aq Mt manu@freebsd.org . Index: head/sys/arm/allwinner/a10/a10_padconf.c =================================================================== --- head/sys/arm/allwinner/a10/a10_padconf.c (revision 355356) +++ head/sys/arm/allwinner/a10/a10_padconf.c (revision 355357) @@ -1,231 +1,230 @@ /*- * Copyright (c) 2016 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #ifdef SOC_ALLWINNER_A10 const static struct allwinner_pins a10_pins[] = { {"PA0", 0, 0, {"gpio_in", "gpio_out", "emac", "spi1", "uart2", NULL, NULL, NULL}}, {"PA1", 0, 1, {"gpio_in", "gpio_out", "emac", "spi1", "uart2", NULL, NULL, NULL}}, {"PA2", 0, 2, {"gpio_in", "gpio_out", "emac", "spi1", "uart2", NULL, NULL, NULL}}, {"PA3", 0, 3, {"gpio_in", "gpio_out", "emac", "spi1", "uart2", NULL, NULL, NULL}}, {"PA4", 0, 4, {"gpio_in", "gpio_out", "emac", "spi1", NULL, NULL, NULL, NULL}}, {"PA5", 0, 5, {"gpio_in", "gpio_out", "emac", "spi3", NULL, NULL, NULL, NULL}}, {"PA6", 0, 6, {"gpio_in", "gpio_out", "emac", "spi3", NULL, NULL, NULL, NULL}}, {"PA7", 0, 7, {"gpio_in", "gpio_out", "emac", "spi3", NULL, NULL, NULL, NULL}}, {"PA8", 0, 8, {"gpio_in", "gpio_out", "emac", "spi3", NULL, NULL, NULL, NULL}}, {"PA9", 0, 9, {"gpio_in", "gpio_out", "emac", "spi3", NULL, NULL, NULL, NULL}}, {"PA10", 0, 10, {"gpio_in", "gpio_out", "emac", NULL, "uart1", NULL, NULL, NULL}}, {"PA11", 0, 11, {"gpio_in", "gpio_out", "emac", NULL, "uart1", NULL, NULL, NULL}}, {"PA12", 0, 12, {"gpio_in", "gpio_out", "emac", "uart6", "uart1", NULL, NULL, NULL}}, {"PA13", 0, 13, {"gpio_in", "gpio_out", "emac", "uart6", "uart1", NULL, NULL, NULL}}, {"PA14", 0, 14, {"gpio_in", "gpio_out", "emac", "uart7", "uart1", NULL, NULL, NULL}}, {"PA15", 0, 15, {"gpio_in", "gpio_out", "emac", "uart7", "uart1", NULL, NULL, NULL}}, {"PA16", 0, 16, {"gpio_in", "gpio_out", NULL, "can", "uart1", NULL, NULL, NULL}}, {"PA17", 0, 17, {"gpio_in", "gpio_out", NULL, "can", "uart1", NULL, NULL, NULL}}, {"PB0", 1, 0, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}}, {"PB1", 1, 1, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}}, {"PB2", 1, 2, {"gpio_in", "gpio_out", "pwm", NULL, NULL, NULL, NULL, NULL}}, {"PB3", 1, 3, {"gpio_in", "gpio_out", "ir0", NULL, NULL, NULL, NULL, NULL}}, {"PB4", 1, 4, {"gpio_in", "gpio_out", "ir0", NULL, NULL, NULL, NULL, NULL}}, {"PB5", 1, 5, {"gpio_in", "gpio_out", "i2s", "ac97", NULL, NULL, NULL, NULL}}, {"PB6", 1, 6, {"gpio_in", "gpio_out", "i2s", "ac97", NULL, NULL, NULL, NULL}}, {"PB7", 1, 7, {"gpio_in", "gpio_out", "i2s", "ac97", NULL, NULL, NULL, NULL}}, {"PB8", 1, 8, {"gpio_in", "gpio_out", "i2s", "ac97", NULL, NULL, NULL, NULL}}, {"PB9", 1, 9, {"gpio_in", "gpio_out", "i2s", NULL, NULL, NULL, NULL, NULL}}, {"PB10", 1, 10, {"gpio_in", "gpio_out", "i2s", NULL, NULL, NULL, NULL, NULL}}, {"PB11", 1, 11, {"gpio_in", "gpio_out", "i2s", NULL, NULL, NULL, NULL, NULL}}, {"PB12", 1, 12, {"gpio_in", "gpio_out", "i2s", "ac97", NULL, NULL, NULL, NULL}}, {"PB13", 1, 13, {"gpio_in", "gpio_out", "spi2", NULL, NULL, NULL, NULL, NULL}}, {"PB14", 1, 14, {"gpio_in", "gpio_out", "spi2", "jtag", NULL, NULL, NULL, NULL}}, {"PB15", 1, 15, {"gpio_in", "gpio_out", "spi2", "jtag", NULL, NULL, NULL, NULL}}, {"PB16", 1, 16, {"gpio_in", "gpio_out", "spi2", "jtag", NULL, NULL, NULL, NULL}}, {"PB17", 1, 17, {"gpio_in", "gpio_out", "spi2", "jtag", NULL, NULL, NULL, NULL}}, {"PB18", 1, 18, {"gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, NULL, NULL}}, {"PB19", 1, 19, {"gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, NULL, NULL}}, {"PB20", 1, 20, {"gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, NULL, NULL}}, {"PB21", 1, 21, {"gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, NULL, NULL}}, {"PB22", 1, 22, {"gpio_in", "gpio_out", "uart0", "ir1", NULL, NULL, NULL, NULL}}, {"PB23", 1, 23, {"gpio_in", "gpio_out", "uart0", "ir1", NULL, NULL, NULL, NULL}}, {"PC0", 2, 0, {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}}, {"PC1", 2, 1, {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}}, {"PC2", 2, 2, {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}}, {"PC3", 2, 3, {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}}, {"PC4", 2, 4, {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}}, {"PC5", 2, 5, {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}}, {"PC6", 2, 6, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC7", 2, 7, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC8", 2, 8, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC9", 2, 9, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC10", 2, 10, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC11", 2, 11, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC12", 2, 12, {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}}, {"PC13", 2, 13, {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}}, {"PC14", 2, 14, {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}}, {"PC15", 2, 15, {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}}, {"PC16", 2, 16, {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}}, {"PC17", 2, 17, {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}}, {"PC18", 2, 18, {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}}, {"PC19", 2, 19, {"gpio_in", "gpio_out", "nand", "spi2", NULL, NULL, NULL, NULL}}, {"PC20", 2, 20, {"gpio_in", "gpio_out", "nand", "spi2", NULL, NULL, NULL, NULL}}, {"PC21", 2, 21, {"gpio_in", "gpio_out", "nand", "spi2", NULL, NULL, NULL, NULL}}, {"PC22", 2, 22, {"gpio_in", "gpio_out", "nand", "spi2", NULL, NULL, NULL, NULL}}, {"PC23", 2, 23, {"gpio_in", "gpio_out", "spi0", NULL, NULL, NULL, NULL, NULL}}, {"PC24", 2, 24, {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}}, {"PD0", 3, 0, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD1", 3, 1, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD2", 3, 2, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD3", 3, 3, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD4", 3, 4, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD5", 3, 5, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD6", 3, 6, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD7", 3, 7, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD8", 3, 8, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD9", 3, 9, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD10", 3, 10, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, {"PD11", 3, 11, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, {"PD12", 3, 12, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, {"PD13", 3, 13, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, {"PD14", 3, 14, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, {"PD15", 3, 15, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, {"PD16", 3, 16, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, {"PD17", 3, 17, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, {"PD18", 3, 18, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, {"PD19", 3, 19, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, {"PD20", 3, 20, {"gpio_in", "gpio_out", "lcd0", "csi1", NULL, NULL, NULL, NULL}}, {"PD21", 3, 21, {"gpio_in", "gpio_out", "lcd0", "sim", NULL, NULL, NULL, NULL}}, {"PD22", 3, 22, {"gpio_in", "gpio_out", "lcd0", "sim", NULL, NULL, NULL, NULL}}, {"PD23", 3, 23, {"gpio_in", "gpio_out", "lcd0", "sim", NULL, NULL, NULL, NULL}}, {"PD24", 3, 24, {"gpio_in", "gpio_out", "lcd0", "sim", NULL, NULL, NULL, NULL}}, {"PD25", 3, 25, {"gpio_in", "gpio_out", "lcd0", "sim", NULL, NULL, NULL, NULL}}, {"PD26", 3, 26, {"gpio_in", "gpio_out", "lcd0", "sim", NULL, NULL, NULL, NULL}}, {"PD27", 3, 27, {"gpio_in", "gpio_out", "lcd0", "sim", NULL, NULL, NULL, NULL}}, {"PE0", 4, 0, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE1", 4, 1, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE2", 4, 2, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE3", 4, 3, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE4", 4, 4, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE5", 4, 5, {"gpio_in", "gpio_out", "ts0", "csi0", "sim", NULL, NULL, NULL}}, {"PE6", 4, 6, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE7", 4, 7, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE8", 4, 8, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE9", 4, 9, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE10", 4, 10, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE11", 4, 11, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PF0", 5, 0, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, {"PF1", 5, 1, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, {"PF2", 5, 2, {"gpio_in", "gpio_out", "mmc0", NULL, "uart0", NULL, NULL, NULL}}, {"PF3", 5, 3, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, {"PF4", 5, 4, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, {"PF5", 5, 5, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, {"PG0", 6, 0, {"gpio_in", "gpio_out", "ts1", "csi1", "mmc1", NULL, NULL, NULL}}, {"PG1", 6, 1, {"gpio_in", "gpio_out", "ts1", "csi1", "mmc1", NULL, NULL, NULL}}, {"PG2", 6, 2, {"gpio_in", "gpio_out", "ts1", "csi1", "mmc1", NULL, NULL, NULL}}, {"PG3", 6, 3, {"gpio_in", "gpio_out", "ts1", "csi1", "mmc1", NULL, NULL, NULL}}, {"PG4", 6, 4, {"gpio_in", "gpio_out", "ts1", "csi1", "mmc1", "csi0", NULL, NULL}}, {"PG5", 6, 5, {"gpio_in", "gpio_out", "ts1", "csi1", "mmc1", "csi0", NULL, NULL}}, {"PG6", 6, 6, {"gpio_in", "gpio_out", "ts1", "csi1", "uart3", "csi0", NULL, NULL}}, {"PG7", 6, 7, {"gpio_in", "gpio_out", "ts1", "csi1", "uart3", "csi0", NULL, NULL}}, {"PG8", 6, 8, {"gpio_in", "gpio_out", "ts1", "csi1", "uart3", "csi0", NULL, NULL}}, {"PG9", 6, 9, {"gpio_in", "gpio_out", "ts1", "csi1", "uart3", "csi0", NULL, NULL}}, {"PG10", 6, 10, {"gpio_in", "gpio_out", "ts1", "csi1", "uart4", "csi0", NULL, NULL}}, {"PG11", 6, 11, {"gpio_in", "gpio_out", "ts1", "csi1", "uart4", "csi0", NULL, NULL}}, {"PH0", 7, 0, {"gpio_in", "gpio_out", "lcd1", "pata", "uart3", NULL, "eint0", "csi1"}, 6, 0}, {"PH1", 7, 1, {"gpio_in", "gpio_out", "lcd1", "pata", "uart3", NULL, "eint1", "csi1"}, 6, 1}, {"PH2", 7, 2, {"gpio_in", "gpio_out", "lcd1", "pata", "uart3", NULL, "eint2", "csi1"}, 6, 2}, {"PH3", 7, 3, {"gpio_in", "gpio_out", "lcd1", "pata", "uart3", NULL, "eint3", "csi1"}, 6, 3}, {"PH4", 7, 4, {"gpio_in", "gpio_out", "lcd1", "pata", "uart4", NULL, "eint4", "csi1"}, 6, 4}, {"PH5", 7, 5, {"gpio_in", "gpio_out", "lcd1", "pata", "uart4", NULL, "eint5", "csi1"}, 6, 5}, {"PH6", 7, 6, {"gpio_in", "gpio_out", "lcd1", "pata", "uart5", "ms", "eint6", "csi1"}, 6, 6}, {"PH7", 7, 7, {"gpio_in", "gpio_out", "lcd1", "pata", "uart5", "ms", "eint7", "csi1"}, 6, 7}, {"PH8", 7, 8, {"gpio_in", "gpio_out", "lcd1", "pata", "keypad", "ms", "eint8", "csi1"}, 6, 8}, {"PH9", 7, 9, {"gpio_in", "gpio_out", "lcd1", "pata", "keypad", "ms", "eint9", "csi1"}, 6, 9}, {"PH10", 7, 10, {"gpio_in", "gpio_out", "lcd1", "pata", "keypad", "ms", "eint10", "csi1"}, 6, 10}, {"PH11", 7, 11, {"gpio_in", "gpio_out", "lcd1", "pata", "keypad", "ms", "eint11", "csi1"}, 6, 11}, {"PH12", 7, 12, {"gpio_in", "gpio_out", "lcd1", "pata", "ps2", NULL, "eint12", "csi1"}, 6, 12}, {"PH13", 7, 13, {"gpio_in", "gpio_out", "lcd1", "pata", "ps2", "sim", "eint13", "csi1"}, 6, 13}, {"PH14", 7, 14, {"gpio_in", "gpio_out", "lcd1", "pata", "keypad", "sim", "eint14", "csi1"}, 6, 14}, {"PH15", 7, 15, {"gpio_in", "gpio_out", "lcd1", "pata", "keypad", "sim", "eint15", "csi1"}, 6, 15}, {"PH16", 7, 16, {"gpio_in", "gpio_out", "lcd1", "pata", "keypad", NULL, "eint16", "csi1"}, 6, 16}, {"PH17", 7, 17, {"gpio_in", "gpio_out", "lcd1", "pata", "keypad", "sim", "eint17", "csi1"}, 6, 17}, {"PH18", 7, 18, {"gpio_in", "gpio_out", "lcd1", "pata", "keypad", "sim", "eint18", "csi1"}, 6, 18}, {"PH19", 7, 19, {"gpio_in", "gpio_out", "lcd1", "pata", "keypad", "sim", "eint19", "csi1"}, 6, 19}, {"PH20", 7, 20, {"gpio_in", "gpio_out", "lcd1", "pata", "can", NULL, "eint20", "csi1"}, 6, 20}, {"PH21", 7, 21, {"gpio_in", "gpio_out", "lcd1", "pata", "can", NULL, "eint21", "csi1"}, 6, 21}, {"PH22", 7, 22, {"gpio_in", "gpio_out", "lcd1", "pata", "keypad", "mmc1", NULL, "csi1"}}, {"PH23", 7, 23, {"gpio_in", "gpio_out", "lcd1", "pata", "keypad", "mmc1", NULL, "csi1"}}, {"PH24", 7, 24, {"gpio_in", "gpio_out", "lcd1", "pata", "keypad", "mmc1", NULL, "csi1"}}, {"PH25", 7, 25, {"gpio_in", "gpio_out", "lcd1", "pata", "keypad", "mmc1", NULL, "csi1"}}, {"PH26", 7, 26, {"gpio_in", "gpio_out", "lcd1", "pata", "keypad", "mmc1", NULL, "csi1"}}, {"PH27", 7, 27, {"gpio_in", "gpio_out", "lcd1", "pata", "keypad", "mmc1", NULL, "csi1"}}, {"PI0", 8, 0, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, {"PI1", 8, 1, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, {"PI2", 8, 2, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, {"PI3", 8, 3, {"gpio_in", "gpio_out", "pwm", NULL, NULL, NULL, NULL, NULL}}, {"PI4", 8, 4, {"gpio_in", "gpio_out", "mmc3", NULL, NULL, NULL, NULL, NULL}}, {"PI5", 8, 5, {"gpio_in", "gpio_out", "mmc3", NULL, NULL, NULL, NULL, NULL}}, {"PI6", 8, 6, {"gpio_in", "gpio_out", "mmc3", NULL, NULL, NULL, NULL, NULL}}, {"PI7", 8, 7, {"gpio_in", "gpio_out", "mmc3", NULL, NULL, NULL, NULL, NULL}}, {"PI8", 8, 8, {"gpio_in", "gpio_out", "mmc3", NULL, NULL, NULL, NULL, NULL}}, {"PI9", 8, 9, {"gpio_in", "gpio_out", "mmc3", NULL, NULL, NULL, NULL, NULL}}, {"PI10", 8, 10, {"gpio_in", "gpio_out", "spi0", "uart5", NULL, NULL, "eint22", NULL}, 6, 22}, {"PI11", 8, 11, {"gpio_in", "gpio_out", "spi0", "uart5", NULL, NULL, "eint23", NULL}, 6, 23}, {"PI12", 8, 12, {"gpio_in", "gpio_out", "spi0", "uart6", NULL, NULL, "eint24", NULL}, 6, 24}, {"PI13", 8, 13, {"gpio_in", "gpio_out", "spi0", "uart6", NULL, NULL, "eint25", NULL}, 6, 25}, {"PI14", 8, 14, {"gpio_in", "gpio_out", "spi0", "ps2", "timer4", NULL, "eint26", NULL}, 6, 26}, {"PI15", 8, 15, {"gpio_in", "gpio_out", "spi1", "ps2", "timer5", NULL, "eint27", NULL}, 6, 27}, {"PI16", 8, 16, {"gpio_in", "gpio_out", "spi1", "uart2", NULL, NULL, "eint28", NULL}, 6, 28}, {"PI17", 8, 17, {"gpio_in", "gpio_out", "spi1", "uart2", NULL, NULL, "eint29", NULL}, 6, 29}, {"PI18", 8, 18, {"gpio_in", "gpio_out", "spi1", "uart2", NULL, NULL, "eint30", NULL}, 6, 30}, {"PI19", 8, 19, {"gpio_in", "gpio_out", "spi1", "uart2", NULL, NULL, "eint31", NULL}, 6, 31}, {"PI20", 8, 20, {"gpio_in", "gpio_out", "ps2", "uart7", "hdmi", NULL, NULL, NULL}}, {"PI21", 8, 21, {"gpio_in", "gpio_out", "ps2", "uart7", "hdmi", NULL, NULL, NULL}}, }; const struct allwinner_padconf a10_padconf = { .npins = sizeof(a10_pins) / sizeof(struct allwinner_pins), .pins = a10_pins, }; #endif /* SOC_ALLWINNER_A10 */ Index: head/sys/arm/allwinner/a13/a13_padconf.c =================================================================== --- head/sys/arm/allwinner/a13/a13_padconf.c (revision 355356) +++ head/sys/arm/allwinner/a13/a13_padconf.c (revision 355357) @@ -1,129 +1,128 @@ /*- * Copyright (c) 2016 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #ifdef SOC_ALLWINNER_A13 const static struct allwinner_pins a13_pins[] = { {"PB0", 1, 0, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}}, {"PB1", 1, 1, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}}, {"PB2", 1, 2, {"gpio_in", "gpio_out", "pwm", NULL, NULL, NULL, "eint16", NULL}, 6, 16}, {"PB3", 1, 3, {"gpio_in", "gpio_out", "ir0", NULL, NULL, NULL, "eint17", NULL}, 6, 17}, {"PB4", 1, 4, {"gpio_in", "gpio_out", "ir0", NULL, NULL, NULL, "eint18", NULL}, 6, 18}, {"PB10", 1, 10, {"gpio_in", "gpio_out", "spi2", NULL, NULL, NULL, "eint24", NULL}, 6, 24}, {"PB15", 1, 15, {"gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, NULL, NULL}}, {"PB16", 1, 16, {"gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, NULL, NULL}}, {"PB17", 1, 17, {"gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, NULL, NULL}}, {"PB18", 1, 18, {"gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, NULL, NULL}}, {"PC0", 2, 0, {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}}, {"PC1", 2, 1, {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}}, {"PC2", 2, 2, {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}}, {"PC3", 2, 3, {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}}, {"PC4", 2, 4, {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}}, {"PC5", 2, 5, {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}}, {"PC6", 2, 6, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC7", 2, 7, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC8", 2, 8, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC9", 2, 9, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC10", 2, 10, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC11", 2, 11, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC12", 2, 12, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC13", 2, 13, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC14", 2, 14, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC15", 2, 15, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC19", 2, 19, {"gpio_in", "gpio_out", "nand", NULL, "uart3", NULL, NULL, NULL}}, {"PD2", 3, 2, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD3", 3, 3, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD4", 3, 4, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD5", 3, 5, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD6", 3, 6, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD7", 3, 7, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD10", 3, 10, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD11", 3, 11, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD12", 3, 12, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD13", 3, 13, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD14", 3, 14, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD15", 3, 15, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD18", 3, 18, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD19", 3, 19, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD20", 3, 20, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD21", 3, 21, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD22", 3, 22, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD23", 3, 23, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD24", 3, 24, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD25", 3, 25, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD26", 3, 26, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD27", 3, 27, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PE0", 4, 0, {"gpio_in", NULL, NULL, "csi0", "spi2", NULL, "eint14", NULL}, 6, 14}, {"PE1", 4, 1, {"gpio_in", NULL, NULL, "csi0", "spi2", NULL, "eint15", NULL}, 6, 15}, {"PE2", 4, 2, {"gpio_in", NULL, NULL, "csi0", "spi2", NULL, NULL, NULL}}, {"PE3", 4, 3, {"gpio_in", "gpio_out", NULL, "csi0", "spi2", NULL, NULL, NULL}}, {"PE4", 4, 4, {"gpio_in", "gpio_out", NULL, "csi0", "mmc2", NULL, NULL, NULL}}, {"PE5", 4, 5, {"gpio_in", "gpio_out", NULL, "csi0", "mmc2", NULL, NULL, NULL}}, {"PE6", 4, 6, {"gpio_in", "gpio_out", NULL, "csi0", "mmc2", NULL, NULL, NULL}}, {"PE7", 4, 7, {"gpio_in", "gpio_out", NULL, "csi0", "mmc2", NULL, NULL, NULL}}, {"PE8", 4, 8, {"gpio_in", "gpio_out", NULL, "csi0", "mmc2", NULL, NULL, NULL}}, {"PE9", 4, 9, {"gpio_in", "gpio_out", NULL, "csi0", "mmc2", NULL, NULL, NULL}}, {"PE10", 4, 10, {"gpio_in", "gpio_out", NULL, "csi0", "uart1", NULL, NULL, NULL}}, {"PE11", 4, 11, {"gpio_in", "gpio_out", NULL, "csi0", "uart1", NULL, NULL, NULL}}, {"PF0", 5, 0, {"gpio_in", "gpio_out", "mmc0", NULL, NULL, NULL, NULL, NULL}}, {"PF1", 5, 1, {"gpio_in", "gpio_out", "mmc0", NULL, NULL, NULL, NULL, NULL}}, {"PF2", 5, 2, {"gpio_in", "gpio_out", "mmc0", NULL, NULL, NULL, NULL, NULL}}, {"PF3", 5, 3, {"gpio_in", "gpio_out", "mmc0", NULL, NULL, NULL, NULL, NULL}}, {"PF4", 5, 4, {"gpio_in", "gpio_out", "mmc0", NULL, NULL, NULL, NULL, NULL}}, {"PF5", 5, 5, {"gpio_in", "gpio_out", "mmc0", NULL, NULL, NULL, NULL, NULL}}, {"PG0", 6, 0, {"gpio_in", NULL, NULL, NULL, NULL, NULL, "eint0", NULL}, 6, 0}, {"PG1", 6, 1, {"gpio_in", NULL, NULL, NULL, NULL, NULL, "eint1", NULL}, 6, 1}, {"PG2", 6, 2, {"gpio_in", NULL, NULL, NULL, NULL, NULL, "eint2", NULL}, 6, 2}, {"PG3", 6, 3, {"gpio_in", "gpio_out", "mmc1", NULL, "uart1", NULL, "eint3", NULL}, 6, 3}, {"PG4", 6, 4, {"gpio_in", "gpio_out", "mmc1", NULL, "uart1", NULL, "eint4", NULL}, 6, 4}, {"PG9", 6, 9, {"gpio_in", "gpio_out", "spi1", "uart3", NULL, NULL, "eint9", NULL}, 6, 9}, {"PG10", 6, 10, {"gpio_in", "gpio_out", "spi1", "uart3", NULL, NULL, "eint10", NULL}, 6, 10}, {"PG11", 6, 11, {"gpio_in", "gpio_out", "spi1", "uart3", NULL, NULL, "eint11", NULL}, 6, 11}, {"PG12", 6, 12, {"gpio_in", "gpio_out", "spi1", "uart3", NULL, NULL, "eint12", NULL}, 6, 12}, }; const struct allwinner_padconf a13_padconf = { .npins = sizeof(a13_pins) / sizeof(struct allwinner_pins), .pins = a13_pins, }; #endif /* SOC_ALLWINNER_A13 */ Index: head/sys/arm/allwinner/a20/a20_padconf.c =================================================================== --- head/sys/arm/allwinner/a20/a20_padconf.c (revision 355356) +++ head/sys/arm/allwinner/a20/a20_padconf.c (revision 355357) @@ -1,231 +1,230 @@ /*- * Copyright (c) 2016 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #ifdef SOC_ALLWINNER_A20 const static struct allwinner_pins a20_pins[] = { {"PA0", 0, 0, {"gpio_in", "gpio_out", "emac", "spi1", "uart2", "gmac", NULL, NULL}}, {"PA1", 0, 1, {"gpio_in", "gpio_out", "emac", "spi1", "uart2", "gmac", NULL, NULL}}, {"PA2", 0, 2, {"gpio_in", "gpio_out", "emac", "spi1", "uart2", "gmac", NULL, NULL}}, {"PA3", 0, 3, {"gpio_in", "gpio_out", "emac", "spi1", "uart2", "gmac", NULL, NULL}}, {"PA4", 0, 4, {"gpio_in", "gpio_out", "emac", "spi1", NULL, "gmac", NULL, NULL}}, {"PA5", 0, 5, {"gpio_in", "gpio_out", "emac", "spi3", NULL, "gmac", NULL, NULL}}, {"PA6", 0, 6, {"gpio_in", "gpio_out", "emac", "spi3", NULL, "gmac", NULL, NULL}}, {"PA7", 0, 7, {"gpio_in", "gpio_out", "emac", "spi3", NULL, "gmac", NULL, NULL}}, {"PA8", 0, 8, {"gpio_in", "gpio_out", "emac", "spi3", NULL, "gmac", NULL, NULL}}, {"PA9", 0, 9, {"gpio_in", "gpio_out", "emac", "spi3", NULL, "gmac", "i2c1", NULL}}, {"PA10", 0, 10, {"gpio_in", "gpio_out", "emac", NULL, "uart1", "gmac", NULL, NULL}}, {"PA11", 0, 11, {"gpio_in", "gpio_out", "emac", NULL, "uart1", "gmac", NULL, NULL}}, {"PA12", 0, 12, {"gpio_in", "gpio_out", "emac", "uart6", "uart1", "gmac", NULL, NULL}}, {"PA13", 0, 13, {"gpio_in", "gpio_out", "emac", "uart6", "uart1", "gmac", NULL, NULL}}, {"PA14", 0, 14, {"gpio_in", "gpio_out", "emac", "uart7", "uart1", "gmac", "i2c1", NULL}}, {"PA15", 0, 15, {"gpio_in", "gpio_out", "emac", "uart7", "uart1", "gmac", "i2c1", NULL}}, {"PA16", 0, 16, {"gpio_in", "gpio_out", NULL, "can", "uart1", "gmac", "i2c1", NULL}}, {"PA17", 0, 17, {"gpio_in", "gpio_out", NULL, "can", "uart1", "gmac", "i2c1", NULL}}, {"PB0", 1, 0, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}}, {"PB1", 1, 1, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}}, {"PB2", 1, 2, {"gpio_in", "gpio_out", "pwm", NULL, NULL, NULL, NULL, NULL}}, {"PB3", 1, 3, {"gpio_in", "gpio_out", "ir0", NULL, "spdif", NULL, NULL, NULL}}, {"PB4", 1, 4, {"gpio_in", "gpio_out", "ir0", NULL, NULL, NULL, NULL, NULL}}, {"PB5", 1, 5, {"gpio_in", "gpio_out", "i2s0", "ac97", NULL, NULL, NULL, NULL}}, {"PB6", 1, 6, {"gpio_in", "gpio_out", "i2c0", "ac97", NULL, NULL, NULL, NULL}}, {"PB7", 1, 7, {"gpio_in", "gpio_out", "i2c0", "ac97", NULL, NULL, NULL, NULL}}, {"PB8", 1, 8, {"gpio_in", "gpio_out", "i2c0", "ac97", NULL, NULL, NULL, NULL}}, {"PB9", 1, 9, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}}, {"PB10", 1, 10, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}}, {"PB11", 1, 11, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}}, {"PB12", 1, 12, {"gpio_in", "gpio_out", "i2c0", "ac97", "spdif", NULL, NULL, NULL}}, {"PB13", 1, 13, {"gpio_in", "gpio_out", "spi2", NULL, "spdif", NULL, NULL, NULL}}, {"PB14", 1, 14, {"gpio_in", "gpio_out", "spi2", "jtag", NULL, NULL, NULL, NULL}}, {"PB15", 1, 15, {"gpio_in", "gpio_out", "spi2", "jtag", NULL, NULL, NULL, NULL}}, {"PB16", 1, 16, {"gpio_in", "gpio_out", "spi2", "jtag", NULL, NULL, NULL, NULL}}, {"PB17", 1, 17, {"gpio_in", "gpio_out", "spi2", "jtag", NULL, NULL, NULL, NULL}}, {"PB18", 1, 18, {"gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, NULL, NULL}}, {"PB19", 1, 19, {"gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, NULL, NULL}}, {"PB20", 1, 20, {"gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, NULL, NULL}}, {"PB21", 1, 21, {"gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, NULL, NULL}}, {"PB22", 1, 22, {"gpio_in", "gpio_out", "uart0", "ir1", NULL, NULL, NULL, NULL}}, {"PB23", 1, 23, {"gpio_in", "gpio_out", "uart0", "ir1", NULL, NULL, NULL, NULL}}, {"PC0", 2, 0, {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}}, {"PC1", 2, 1, {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}}, {"PC2", 2, 2, {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}}, {"PC3", 2, 3, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC4", 2, 4, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC5", 2, 5, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC6", 2, 6, {"gpio_in", "gpio_out", "nand0", "mmc2", NULL, NULL, NULL, NULL}}, {"PC7", 2, 7, {"gpio_in", "gpio_out", "nand0", "mmc2", NULL, NULL, NULL, NULL}}, {"PC8", 2, 8, {"gpio_in", "gpio_out", "nand0", "mmc2", NULL, NULL, NULL, NULL}}, {"PC9", 2, 9, {"gpio_in", "gpio_out", "nand0", "mmc2", NULL, NULL, NULL, NULL}}, {"PC10", 2, 10, {"gpio_in", "gpio_out", "nand0", "mmc2", NULL, NULL, NULL, NULL}}, {"PC11", 2, 11, {"gpio_in", "gpio_out", "nand0", "mmc2", NULL, NULL, NULL, NULL}}, {"PC12", 2, 12, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC13", 2, 13, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC14", 2, 14, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC15", 2, 15, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC16", 2, 16, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC17", 2, 17, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC18", 2, 18, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC19", 2, 19, {"gpio_in", "gpio_out", "nand0", "spi2", NULL, NULL, "eint12", NULL}, 6, 12}, {"PC20", 2, 20, {"gpio_in", "gpio_out", "nand0", "spi2", NULL, NULL, "eint13", NULL}, 6, 13}, {"PC21", 2, 21, {"gpio_in", "gpio_out", "nand0", "spi2", NULL, NULL, "eint14", NULL}, 6, 14}, {"PC22", 2, 22, {"gpio_in", "gpio_out", "nand0", "spi2", NULL, NULL, "eint15", NULL}, 6, 15}, {"PC23", 2, 23, {"gpio_in", "gpio_out", NULL, "spi0", NULL, NULL, NULL, NULL}}, {"PC24", 2, 24, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PD0", 3, 0, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD1", 3, 1, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD2", 3, 2, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD3", 3, 3, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD4", 3, 4, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD5", 3, 5, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD6", 3, 6, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD7", 3, 7, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD8", 3, 8, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD9", 3, 9, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD10", 3, 10, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD11", 3, 11, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD12", 3, 12, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD13", 3, 13, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD14", 3, 14, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD15", 3, 15, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD16", 3, 16, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD17", 3, 17, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD18", 3, 18, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD19", 3, 19, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD20", 3, 20, {"gpio_in", "gpio_out", "lcd0", "csi1", NULL, NULL, NULL, NULL}}, {"PD21", 3, 21, {"gpio_in", "gpio_out", "lcd0", "sim", NULL, NULL, NULL, NULL}}, {"PD22", 3, 22, {"gpio_in", "gpio_out", "lcd0", "sim", NULL, NULL, NULL, NULL}}, {"PD23", 3, 23, {"gpio_in", "gpio_out", "lcd0", "sim", NULL, NULL, NULL, NULL}}, {"PD24", 3, 24, {"gpio_in", "gpio_out", "lcd0", "sim", NULL, NULL, NULL, NULL}}, {"PD25", 3, 25, {"gpio_in", "gpio_out", "lcd0", "sim", NULL, NULL, NULL, NULL}}, {"PD26", 3, 26, {"gpio_in", "gpio_out", "lcd0", "sim", NULL, NULL, NULL, NULL}}, {"PD27", 3, 27, {"gpio_in", "gpio_out", "lcd0", "sim", NULL, NULL, NULL, NULL}}, {"PE0", 4, 0, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE1", 4, 1, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE2", 4, 2, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE3", 4, 3, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE4", 4, 4, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE5", 4, 5, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE6", 4, 6, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE7", 4, 7, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE8", 4, 8, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE9", 4, 9, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE10", 4, 10, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PE11", 4, 11, {"gpio_in", "gpio_out", "ts0", "csi0", NULL, NULL, NULL, NULL}}, {"PF0", 5, 0, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, {"PF1", 5, 1, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, {"PF2", 5, 2, {"gpio_in", "gpio_out", "mmc0", NULL, "uart0", NULL, NULL, NULL}}, {"PF3", 5, 3, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, {"PF4", 5, 4, {"gpio_in", "gpio_out", "mmc0", NULL, "uart0", NULL, NULL, NULL}}, {"PF5", 5, 5, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, {"PG0", 6, 0, {"gpio_in", "gpio_out", "ts1", "csi1", "mmc1", NULL, NULL, NULL}}, {"PG1", 6, 1, {"gpio_in", "gpio_out", "ts1", "csi1", "mmc1", NULL, NULL, NULL}}, {"PG2", 6, 2, {"gpio_in", "gpio_out", "ts1", "csi1", "mmc1", NULL, NULL, NULL}}, {"PG3", 6, 3, {"gpio_in", "gpio_out", "ts1", "csi1", "mmc1", NULL, NULL, NULL}}, {"PG4", 6, 4, {"gpio_in", "gpio_out", "ts1", "csi1", "mmc1", "csi0", NULL, NULL}}, {"PG5", 6, 5, {"gpio_in", "gpio_out", "ts1", "csi1", "mmc1", "csi0", NULL, NULL}}, {"PG6", 6, 6, {"gpio_in", "gpio_out", "ts1", "csi1", "uart3", "csi0", NULL, NULL}}, {"PG7", 6, 7, {"gpio_in", "gpio_out", "ts1", "csi1", "uart3", "csi0", NULL, NULL}}, {"PG8", 6, 8, {"gpio_in", "gpio_out", "ts1", "csi1", "uart3", "csi0", NULL, NULL}}, {"PG9", 6, 9, {"gpio_in", "gpio_out", "ts1", "csi1", "uart3", "csi0", NULL, NULL}}, {"PG10", 6, 10, {"gpio_in", "gpio_out", "ts1", "csi1", "uart4", "csi0", NULL, NULL}}, {"PG11", 6, 11, {"gpio_in", "gpio_out", "ts1", "csi1", "uart4", "csi0", NULL, NULL}}, {"PH0", 7, 0, {"gpio_in", "gpio_out", "lcd1", NULL, "uart3", NULL, "eint0", "csi1"}, 6, 0}, {"PH1", 7, 1, {"gpio_in", "gpio_out", "lcd1", NULL, "uart3", NULL, "eint1", "csi1"}, 6, 1}, {"PH2", 7, 2, {"gpio_in", "gpio_out", "lcd1", NULL, "uart3", NULL, "eint2", "csi1"}, 6, 2}, {"PH3", 7, 3, {"gpio_in", "gpio_out", "lcd1", NULL, "uart3", NULL, "eint3", "csi1"}, 6, 3}, {"PH4", 7, 4, {"gpio_in", "gpio_out", "lcd1", NULL, "uart4", NULL, "eint4", "csi1"}, 6, 4}, {"PH5", 7, 5, {"gpio_in", "gpio_out", "lcd1", NULL, "uart4", NULL, "eint5", "csi1"}, 6, 5}, {"PH6", 7, 6, {"gpio_in", "gpio_out", "lcd1", NULL, "uart5", "ms", "eint6", "csi1"}, 6, 6}, {"PH7", 7, 7, {"gpio_in", "gpio_out", "lcd1", NULL, "uart5", "ms", "eint7", "csi1"}, 6, 7}, {"PH8", 7, 8, {"gpio_in", "gpio_out", "lcd1", NULL, "keypad", "ms", "eint8", "csi1"}, 6, 8}, {"PH9", 7, 9, {"gpio_in", "gpio_out", "lcd1", NULL, "keypad", "ms", "eint9", "csi1"}, 6, 9}, {"PH10", 7, 10, {"gpio_in", "gpio_out", "lcd1", NULL, "keypad", "ms", "eint10", "csi1"}, 6, 10}, {"PH11", 7, 11, {"gpio_in", "gpio_out", "lcd1", NULL, "keypad", "ms", "eint11", "csi1"}, 6, 11}, {"PH12", 7, 12, {"gpio_in", "gpio_out", "lcd1", NULL, "ps2", NULL, "eint12", "csi1"}, 6, 12}, {"PH13", 7, 13, {"gpio_in", "gpio_out", "lcd1", NULL, "ps2", "sim", "eint13", "csi1"}, 6, 13}, {"PH14", 7, 14, {"gpio_in", "gpio_out", "lcd1", NULL, "keypad", "sim", "eint14", "csi1"}, 6, 14}, {"PH15", 7, 15, {"gpio_in", "gpio_out", "lcd1", NULL, "keypad", "sim", "eint15", "csi1"}, 6, 15}, {"PH16", 7, 16, {"gpio_in", "gpio_out", "lcd1", NULL, "keypad", "sim", "eint16", "csi1"}, 6, 16}, {"PH17", 7, 17, {"gpio_in", "gpio_out", "lcd1", NULL, "keypad", "sim", "eint17", "csi1"}, 6, 17}, {"PH18", 7, 18, {"gpio_in", "gpio_out", "lcd1", NULL, "keypad", "sim", "eint18", "csi1"}, 6, 18}, {"PH19", 7, 19, {"gpio_in", "gpio_out", "lcd1", NULL, "keypad", "sim", "eint19", "csi1"}, 6, 19}, {"PH20", 7, 20, {"gpio_in", "gpio_out", "lcd1", NULL, "can", NULL, "eint20", "csi1"}, 6, 20}, {"PH21", 7, 21, {"gpio_in", "gpio_out", "lcd1", NULL, "can", NULL, "eint21", "csi1"}, 6, 21}, {"PH22", 7, 22, {"gpio_in", "gpio_out", "lcd1", NULL, "keypad", "mmc1", NULL, "csi1"}}, {"PH23", 7, 23, {"gpio_in", "gpio_out", "lcd1", NULL, "keypad", "mmc1", NULL, "csi1"}}, {"PH24", 7, 24, {"gpio_in", "gpio_out", "lcd1", NULL, "keypad", "mmc1", NULL, "csi1"}}, {"PH25", 7, 25, {"gpio_in", "gpio_out", "lcd1", NULL, "keypad", "mmc1", NULL, "csi1"}}, {"PH26", 7, 26, {"gpio_in", "gpio_out", "lcd1", NULL, "keypad", "mmc1", NULL, "csi1"}}, {"PH27", 7, 27, {"gpio_in", "gpio_out", "lcd1", NULL, "keypad", "mmc1", NULL, "csi1"}}, {"PI0", 8, 0, {"gpio_in", "gpio_out", NULL, "i2c3", NULL, NULL, NULL, NULL}}, {"PI1", 8, 1, {"gpio_in", "gpio_out", NULL, "i2c3", NULL, NULL, NULL, NULL}}, {"PI2", 8, 2, {"gpio_in", "gpio_out", NULL, "i2c4", NULL, NULL, NULL, NULL}}, {"PI3", 8, 3, {"gpio_in", "gpio_out", "pwm", "i2c4", NULL, NULL, NULL, NULL}}, {"PI4", 8, 4, {"gpio_in", "gpio_out", "mmc3", NULL, NULL, NULL, NULL, NULL}}, {"PI5", 8, 5, {"gpio_in", "gpio_out", "mmc3", NULL, NULL, NULL, NULL, NULL}}, {"PI6", 8, 6, {"gpio_in", "gpio_out", "mmc3", NULL, NULL, NULL, NULL, NULL}}, {"PI7", 8, 7, {"gpio_in", "gpio_out", "mmc3", NULL, NULL, NULL, NULL, NULL}}, {"PI8", 8, 8, {"gpio_in", "gpio_out", "mmc3", NULL, NULL, NULL, NULL, NULL}}, {"PI9", 8, 9, {"gpio_in", "gpio_out", "mmc3", NULL, NULL, NULL, NULL, NULL}}, {"PI10", 8, 10, {"gpio_in", "gpio_out", "spi0", "uart5", NULL, NULL, "eint", NULL}}, {"PI11", 8, 11, {"gpio_in", "gpio_out", "spi0", "uart5", NULL, NULL, "eint", NULL}}, {"PI12", 8, 12, {"gpio_in", "gpio_out", "spi0", "uart6", "clk_out_a", NULL, "eint", NULL}}, {"PI13", 8, 13, {"gpio_in", "gpio_out", "spi0", "uart6", "clk_out_b", NULL, "eint", NULL}}, {"PI14", 8, 14, {"gpio_in", "gpio_out", "spi0", "ps2", "timer4", NULL, "eint", NULL}}, {"PI15", 8, 15, {"gpio_in", "gpio_out", "spi1", "ps2", "timer5", NULL, "eint", NULL}}, {"PI16", 8, 16, {"gpio_in", "gpio_out", "spi1", "uart2", NULL, NULL, "eint", NULL}}, {"PI17", 8, 17, {"gpio_in", "gpio_out", "spi1", "uart2", NULL, NULL, "eint", NULL}}, {"PI18", 8, 18, {"gpio_in", "gpio_out", "spi1", "uart2", NULL, NULL, "eint", NULL}}, {"PI19", 8, 19, {"gpio_in", "gpio_out", "spi1", "uart2", NULL, NULL, "eint", NULL}}, {"PI20", 8, 20, {"gpio_in", "gpio_out", "ps2", "uart7", "hdmi", NULL, NULL, NULL}}, {"PI21", 8, 21, {"gpio_in", "gpio_out", "ps2", "uart7", "hdmi", NULL, NULL, NULL}}, }; const struct allwinner_padconf a20_padconf = { .npins = sizeof(a20_pins) / sizeof(struct allwinner_pins), .pins = a20_pins, }; #endif /* SOC_ALLWINNER_A20 */ Index: head/sys/arm/allwinner/a31/a31_padconf.c =================================================================== --- head/sys/arm/allwinner/a31/a31_padconf.c (revision 355356) +++ head/sys/arm/allwinner/a31/a31_padconf.c (revision 355357) @@ -1,220 +1,219 @@ /*- * Copyright (c) 2016 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #ifdef SOC_ALLWINNER_A31 const static struct allwinner_pins a31_pins[] = { {"PA0", 0, 0, {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, "pa_eint0", NULL}, 6, 0}, {"PA1", 0, 1, {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, "pa_eint1", NULL}, 6, 1}, {"PA2", 0, 2, {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, "pa_eint2", NULL}, 6, 2}, {"PA3", 0, 3, {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, "pa_eint3", NULL}, 6, 3}, {"PA4", 0, 4, {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, "pa_eint4", NULL}, 6, 4}, {"PA5", 0, 5, {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, "pa_eint5", NULL}, 6, 5}, {"PA6", 0, 6, {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, "pa_eint6", NULL}, 6, 6}, {"PA7", 0, 7, {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, "pa_eint7", NULL}, 6, 7}, {"PA8", 0, 8, {"gpio_in", "gpio_out", "gmac", "lcd1", NULL, NULL, "pa_eint8", NULL}, 6, 8}, {"PA9", 0, 9, {"gpio_in", "gpio_out", "gmac", "lcd1", NULL, "mmc2", "pa_eint9", NULL}, 6, 9}, {"PA10", 0, 10, {"gpio_in", "gpio_out", "gmac", "lcd1", "mmc3", "mmc2", "pa_eint10", NULL}, 6, 10}, {"PA11", 0, 11, {"gpio_in", "gpio_out", "gmac", "lcd1", "mmc3", "mmc2", "pa_eint11", NULL}, 6, 11}, {"PA12", 0, 12, {"gpio_in", "gpio_out", "gmac", "lcd1", "mmc3", "mmc2", "pa_eint12", NULL}, 6, 12}, {"PA13", 0, 13, {"gpio_in", "gpio_out", "gmac", "lcd1", "mmc3", "mmc2", "pa_eint13", NULL}, 6, 13}, {"PA14", 0, 14, {"gpio_in", "gpio_out", "gmac", "lcd1", "mmc3", "mmc2", "pa_eint14", NULL}, 6, 14}, {"PA15", 0, 15, {"gpio_in", "gpio_out", "gmac", "lcd1", "clk_out_a", NULL, "pa_eint15", NULL}, 6, 15}, {"PA16", 0, 16, {"gpio_in", "gpio_out", "gmac", "lcd1", "dmic", NULL, "pa_eint16", NULL}, 6, 16}, {"PA17", 0, 17, {"gpio_in", "gpio_out", "gmac", "lcd1", "dmic", NULL, "pa_eint17", NULL}, 6, 17}, {"PA18", 0, 18, {"gpio_in", "gpio_out", "gmac", "lcd1", "clk_out_b", NULL, "pa_eint18", NULL}, 6, 18}, {"PA19", 0, 19, {"gpio_in", "gpio_out", "gmac", "lcd1", "pwm3", NULL, "pa_eint19", NULL}, 6, 19}, {"PA20", 0, 20, {"gpio_in", "gpio_out", "gmac", "lcd1", "pwm3", NULL, "pa_eint20", NULL}, 6, 20}, {"PA21", 0, 21, {"gpio_in", "gpio_out", "gmac", "lcd1", "spi3", NULL, "pa_eint21", NULL}, 6, 21}, {"PA22", 0, 22, {"gpio_in", "gpio_out", "gmac", "lcd1", "spi3", NULL, "pa_eint22", NULL}, 6, 22}, {"PA23", 0, 23, {"gpio_in", "gpio_out", "gmac", "lcd1", "spi3", NULL, "pa_eint23", NULL}, 6, 23}, {"PA24", 0, 24, {"gpio_in", "gpio_out", "gmac", "lcd1", "spi3", NULL, "pa_eint24", NULL}, 6, 24}, {"PA25", 0, 25, {"gpio_in", "gpio_out", "gmac", "lcd1", "spi3", NULL, "pa_eint25", NULL}, 6, 25}, {"PA26", 0, 26, {"gpio_in", "gpio_out", "gmac", "lcd1", "clk_out_c", NULL, "pa_eint26", NULL}, 6, 26}, {"PA27", 0, 27, {"gpio_in", "gpio_out", "gmac", "lcd1", NULL, NULL, "pa_eint27", NULL}, 6, 27}, {"PB0", 1, 0, {"gpio_in", "gpio_out", "i2s0", "uart3", "csi", NULL, "pb_eint0", NULL}, 6, 0}, {"PB1", 1, 1, {"gpio_in", "gpio_out", "i2s0", NULL, NULL, NULL, "pb_eint1", NULL}, 6, 1}, {"PB2", 1, 2, {"gpio_in", "gpio_out", "i2s0", NULL, NULL, NULL, "pb_eint2", NULL}, 6, 2}, {"PB3", 1, 3, {"gpio_in", "gpio_out", "i2s0", NULL, NULL, NULL, "pb_eint3", NULL}, 6, 3}, {"PB4", 1, 4, {"gpio_in", "gpio_out", "i2s0", "uart3", NULL, NULL, "pb_eint4", NULL}, 6, 4}, {"PB5", 1, 5, {"gpio_in", "gpio_out", "i2s0", "uart3", "i2c3", NULL, "pb_eint5", NULL}, 6, 5}, {"PB6", 1, 6, {"gpio_in", "gpio_out", "i2s0", "uart3", "i2c3", NULL, "pb_eint6", NULL}, 6, 6}, {"PB7", 1, 7, {"gpio_in", "gpio_out", "i2s0", NULL, NULL, NULL, "pb_eint7", NULL}, 6, 7}, {"PC0", 2, 0, {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}}, {"PC1", 2, 1, {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}}, {"PC2", 2, 2, {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}}, {"PC3", 2, 3, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC4", 2, 4, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC5", 2, 5, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC6", 2, 6, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC7", 2, 7, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC8", 2, 8, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC9", 2, 9, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC10", 2, 10, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC11", 2, 11, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC12", 2, 12, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC13", 2, 13, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC14", 2, 14, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC15", 2, 15, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC16", 2, 16, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}}, {"PC17", 2, 17, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}}, {"PC18", 2, 18, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}}, {"PC19", 2, 19, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}}, {"PC20", 2, 20, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}}, {"PC21", 2, 21, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}}, {"PC22", 2, 22, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}}, {"PC23", 2, 23, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}}, {"PC24", 2, 24, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC25", 2, 25, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC26", 2, 26, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC27", 2, 27, {"gpio_in", "gpio_out", NULL, "spi0",NULL, NULL, NULL, NULL}}, {"PD0", 3, 0, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD1", 3, 1, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD2", 3, 2, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD3", 3, 3, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD4", 3, 4, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD5", 3, 5, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD6", 3, 6, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD7", 3, 7, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD8", 3, 8, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD9", 3, 9, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD10", 3, 10, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, {"PD11", 3, 11, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, {"PD12", 3, 12, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, {"PD13", 3, 13, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, {"PD14", 3, 14, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, {"PD15", 3, 15, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, {"PD16", 3, 16, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, {"PD17", 3, 17, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, {"PD18", 3, 18, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, {"PD19", 3, 19, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, {"PD20", 3, 20, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD21", 3, 21, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD22", 3, 22, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD23", 3, 23, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD24", 3, 24, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD25", 3, 25, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD26", 3, 26, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD27", 3, 27, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PE0", 4, 0, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint0", NULL}, 6, 0}, {"PE1", 4, 1, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint1", NULL}, 6, 1}, {"PE2", 4, 2, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint2", NULL}, 6, 2}, {"PE3", 4, 3, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint3", NULL}, 6, 3}, {"PE4", 4, 4, {"gpio_in", "gpio_out", "csi", "uart5", NULL, NULL, "pe_eint4", NULL}, 6, 4}, {"PE5", 4, 5, {"gpio_in", "gpio_out", "csi", "uart5", NULL, NULL, "pe_eint5", NULL}, 6, 5}, {"PE6", 4, 6, {"gpio_in", "gpio_out", "csi", "uart5", NULL, NULL, "pe_eint6", NULL}, 6, 6}, {"PE7", 4, 7, {"gpio_in", "gpio_out", "csi", "uart5", NULL, NULL, "pe_eint7", NULL}, 6, 7}, {"PE8", 4, 8, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint8", NULL}, 6, 8}, {"PE9", 4, 9, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint9", NULL}, 6, 9}, {"PE10", 4, 10, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint10", NULL}, 6, 10}, {"PE11", 4, 11, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint11", NULL}, 6, 11}, {"PE12", 4, 12, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint12", NULL}, 6, 12}, {"PE13", 4, 13, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint13", NULL}, 6, 13}, {"PE14", 4, 14, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint14", NULL}, 6, 14}, {"PE15", 4, 15, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint15", NULL}, 6, 15}, {"PE16", 4, 16, {"gpio_in", "gpio_out", "csi", NULL, NULL, NULL, "pe_eint16", NULL}, 6, 16}, {"PF0", 5, 0, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, {"PF1", 5, 1, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, {"PF2", 5, 2, {"gpio_in", "gpio_out", "mmc0", NULL, "uart0", NULL, NULL, NULL}}, {"PF3", 5, 3, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, {"PF4", 5, 4, {"gpio_in", "gpio_out", "mmc0", NULL, "uart0", NULL, NULL, NULL}}, {"PF5", 5, 5, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, {"PG0", 6, 0, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint0", NULL}, 6, 0}, {"PG1", 6, 1, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint1", NULL}, 6, 1}, {"PG2", 6, 2, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint2", NULL}, 6, 2}, {"PG3", 6, 3, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint3", NULL}, 6, 3}, {"PG4", 6, 4, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint4", NULL}, 6, 4}, {"PG5", 6, 5, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint5", NULL}, 6, 5}, {"PG6", 6, 6, {"gpio_in", "gpio_out", "uart2", NULL, NULL, NULL, "pg_eint6", NULL}, 6, 6}, {"PG7", 6, 7, {"gpio_in", "gpio_out", "uart2", NULL, NULL, NULL, "pg_eint7", NULL}, 6, 7}, {"PG8", 6, 8, {"gpio_in", "gpio_out", "uart2", NULL, NULL, NULL, "pg_eint8", NULL}, 6, 8}, {"PG9", 6, 9, {"gpio_in", "gpio_out", "uart2", NULL, NULL, NULL, "pg_eint9", NULL}, 6, 9}, {"PG10", 6, 10, {"gpio_in", "gpio_out", "i2c3", "usb", NULL, NULL, "pg_eint10", NULL}, 6, 10}, {"PG11", 6, 11, {"gpio_in", "gpio_out", "i2c3", "usb", NULL, NULL, "pg_eint11", NULL}, 6, 11}, {"PG12", 6, 12, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, "pg_eint12", NULL}, 6, 12}, {"PG13", 6, 13, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, "pg_eint13", NULL}, 6, 13}, {"PG14", 6, 14, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, "pg_eint14", NULL}, 6, 14}, {"PG15", 6, 15, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, "pg_eint15", NULL}, 6, 15}, {"PG16", 6, 16, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, "pg_eint16", NULL}, 6, 16}, {"PG17", 6, 17, {"gpio_in", "gpio_out", "uart4", NULL, NULL, NULL, "pg_eint17", NULL}, 6, 17}, {"PG18", 6, 18, {"gpio_in", "gpio_out", "uart4", NULL, NULL, NULL, "pg_eint18", NULL}, 6, 18}, {"PH0", 7, 0, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, {"PH1", 7, 1, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, {"PH2", 7, 2, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, {"PH3", 7, 3, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, {"PH4", 7, 4, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, {"PH5", 7, 5, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, {"PH6", 7, 6, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, {"PH7", 7, 7, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, {"PH8", 7, 8, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, {"PH9", 7, 9, {"gpio_in", "gpio_out", "spi2", "jtag", "pwm1", NULL, NULL, NULL}}, {"PH10", 7, 10, {"gpio_in", "gpio_out", "spi2", "jtag", "pwm1", NULL, NULL, NULL}}, {"PH11", 7, 11, {"gpio_in", "gpio_out", "spi2", "jtag", "pwm2", NULL, NULL, NULL}}, {"PH12", 7, 12, {"gpio_in", "gpio_out", "spi2", "jtag", "pwm2", NULL, NULL, NULL}}, {"PH13", 7, 13, {"gpio_in", "gpio_out", "pwm0", NULL, NULL, NULL, NULL, NULL}}, {"PH14", 7, 14, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}}, {"PH15", 7, 15, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}}, {"PH16", 7, 16, {"gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, NULL, NULL}}, {"PH17", 7, 17, {"gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, NULL, NULL}}, {"PH18", 7, 18, {"gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, NULL, NULL}}, {"PH19", 7, 19, {"gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, NULL, NULL}}, {"PH20", 7, 20, {"gpio_in", "gpio_out", "uart0", NULL, NULL, NULL, NULL, NULL}}, {"PH21", 7, 21, {"gpio_in", "gpio_out", "uart0", NULL, NULL, NULL, NULL, NULL}}, {"PH22", 7, 22, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, {"PH23", 7, 23, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, {"PH24", 7, 24, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, {"PH25", 7, 25, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, {"PH26", 7, 26, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, {"PH27", 7, 27, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, {"PH28", 7, 28, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, {"PH29", 7, 29, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, {"PH30", 7, 30, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, }; const struct allwinner_padconf a31_padconf = { .npins = nitems(a31_pins), .pins = a31_pins, }; #endif /* SOC_ALLWINNER_A31 */ Index: head/sys/arm/allwinner/a31/a31_r_padconf.c =================================================================== --- head/sys/arm/allwinner/a31/a31_r_padconf.c (revision 355356) +++ head/sys/arm/allwinner/a31/a31_r_padconf.c (revision 355357) @@ -1,66 +1,65 @@ /*- * Copyright (c) 2016 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #if defined(SOC_ALLWINNER_A31) || defined(SOC_ALLWINNER_A31S) const static struct allwinner_pins a31_r_pins[] = { {"PL0", 0, 0, {"gpio_in", "gpio_out", "s_twi", "s_p2wi", NULL, NULL, NULL, NULL}}, {"PL1", 0, 1, {"gpio_in", "gpio_out", "s_twi", "s_p2wi", NULL, NULL, NULL, NULL}}, {"PL2", 0, 2, {"gpio_in", "gpio_out", "s_uart", NULL, NULL, NULL, NULL, NULL}}, {"PL3", 0, 3, {"gpio_in", "gpio_out", "s_uart", NULL, NULL, NULL, NULL, NULL}}, {"PL4", 0, 4, {"gpio_in", "gpio_out", "s_ir", NULL, NULL, NULL, NULL, NULL}}, {"PL5", 0, 5, {"gpio_in", "gpio_out", "pl_eint0", "s_jtag", NULL, NULL, NULL, NULL}, 2, 0}, {"PL6", 0, 6, {"gpio_in", "gpio_out", "pl_eint1", "s_jtag", NULL, NULL, NULL, NULL}, 2, 1}, {"PL7", 0, 7, {"gpio_in", "gpio_out", "pl_eint2", "s_jtag", NULL, NULL, NULL, NULL}, 2, 2}, {"PL8", 0, 8, {"gpio_in", "gpio_out", "pl_eint3", "s_jtag", NULL, NULL, NULL, NULL}, 2, 3}, {"PM0", 1, 0, {"gpio_in", "gpio_out", "pm_eint0", NULL, NULL, NULL, NULL, NULL}, 2, 0}, {"PM1", 1, 1, {"gpio_in", "gpio_out", "pm_eint1", NULL, NULL, NULL, NULL, NULL}, 2, 1}, {"PM2", 1, 2, {"gpio_in", "gpio_out", "pm_eint2", "1wire", NULL, NULL, NULL, NULL}, 2, 2}, {"PM3", 1, 3, {"gpio_in", "gpio_out", "pm_eint3", NULL, NULL, NULL, NULL, NULL}, 2, 3}, {"PM4", 1, 4, {"gpio_in", "gpio_out", "pm_eint4", NULL, NULL, NULL, NULL, NULL}, 2, 4}, {"PM5", 1, 5, {"gpio_in", "gpio_out", "pm_eint5", NULL, NULL, NULL, NULL, NULL}, 2, 5}, {"PM6", 1, 6, {"gpio_in", "gpio_out", "pm_eint6", NULL, NULL, NULL, NULL, NULL}, 2, 6}, {"PM7", 1, 7, {"gpio_in", "gpio_out", "pm_eint7", "rtc", NULL, NULL, NULL, NULL}, 2, 7}, }; const struct allwinner_padconf a31_r_padconf = { .npins = nitems(a31_r_pins), .pins = a31_r_pins, }; #endif Index: head/sys/arm/allwinner/a31/a31s_padconf.c =================================================================== --- head/sys/arm/allwinner/a31/a31s_padconf.c (revision 355356) +++ head/sys/arm/allwinner/a31/a31s_padconf.c (revision 355357) @@ -1,200 +1,199 @@ /*- * Copyright (c) 2016 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #ifdef SOC_ALLWINNER_A31S const static struct allwinner_pins a31s_pins[] = { {"PA0", 0, 0, {"gpio_in", "gpio_out", "gmac", NULL, "uart1", NULL, "pa_eint0", NULL}, 6, 0}, {"PA1", 0, 1, {"gpio_in", "gpio_out", "gmac", NULL, "uart1", NULL, "pa_eint1", NULL}, 6, 1}, {"PA2", 0, 2, {"gpio_in", "gpio_out", "gmac", NULL, "uart1", NULL, "pa_eint2", NULL}, 6, 2}, {"PA3", 0, 3, {"gpio_in", "gpio_out", "gmac", NULL, "uart1", NULL, "pa_eint3", NULL}, 6, 3}, {"PA4", 0, 4, {"gpio_in", "gpio_out", "gmac", NULL, "uart1", NULL, "pa_eint4", NULL}, 6, 4}, {"PA5", 0, 5, {"gpio_in", "gpio_out", "gmac", NULL, "uart1", NULL, "pa_eint5", NULL}, 6, 5}, {"PA6", 0, 6, {"gpio_in", "gpio_out", "gmac", NULL, "uart1", NULL, "pa_eint6", NULL}, 6, 6}, {"PA7", 0, 7, {"gpio_in", "gpio_out", "gmac", NULL, "uart1", NULL, "pa_eint7", NULL}, 6, 7}, {"PA8", 0, 8, {"gpio_in", "gpio_out", "gmac", NULL, NULL, NULL, "pa_eint8", NULL}, 6, 8}, {"PA9", 0, 9, {"gpio_in", "gpio_out", "gmac", NULL, NULL, NULL, "pa_eint9", NULL}, 6, 9}, {"PA10", 0, 10, {"gpio_in", "gpio_out", "gmac", NULL, "mmc3", "mmc2", "pa_eint10", NULL}, 6, 10}, {"PA11", 0, 11, {"gpio_in", "gpio_out", "gmac", NULL, "mmc3", "mmc2", "pa_eint11", NULL}, 6, 11}, {"PA12", 0, 12, {"gpio_in", "gpio_out", "gmac", NULL, "mmc3", "mmc2", "pa_eint12", NULL}, 6, 12}, {"PA13", 0, 13, {"gpio_in", "gpio_out", "gmac", NULL, "mmc3", "mmc2", "pa_eint13", NULL}, 6, 13}, {"PA14", 0, 14, {"gpio_in", "gpio_out", "gmac", NULL, "mmc3", "mmc2", "pa_eint14", NULL}, 6, 14}, {"PA15", 0, 15, {"gpio_in", "gpio_out", "gmac", NULL, "dmic", NULL, "pa_eint15", NULL}, 6, 15}, {"PA16", 0, 16, {"gpio_in", "gpio_out", "gmac", NULL, "dmic", NULL, "pa_eint16", NULL}, 6, 16}, {"PA17", 0, 17, {"gpio_in", "gpio_out", "gmac", NULL, "clk_out_b", NULL, "pa_eint17", NULL}, 6, 17}, {"PA18", 0, 18, {"gpio_in", "gpio_out", "gmac", NULL, "pwm3", NULL, "pa_eint18", NULL}, 6, 18}, {"PA19", 0, 19, {"gpio_in", "gpio_out", "gmac", NULL, "pwm3", NULL, "pa_eint19", NULL}, 6, 19}, {"PA20", 0, 20, {"gpio_in", "gpio_out", "gmac", NULL, "spi3", NULL, "pa_eint20", NULL}, 6, 20}, {"PA21", 0, 21, {"gpio_in", "gpio_out", "gmac", NULL, "spi3", NULL, "pa_eint21", NULL}, 6, 21}, {"PA22", 0, 22, {"gpio_in", "gpio_out", "gmac", NULL, "spi3", NULL, "pa_eint22", NULL}, 6, 22}, {"PA23", 0, 23, {"gpio_in", "gpio_out", "gmac", NULL, "spi3", NULL, "pa_eint23", NULL}, 6, 23}, {"PA24", 0, 24, {"gpio_in", "gpio_out", "gmac", NULL, "spi3", NULL, "pa_eint24", NULL}, 6, 24}, {"PA25", 0, 25, {"gpio_in", "gpio_out", "gmac", NULL, "spi3", NULL, "pa_eint25", NULL}, 6, 25}, {"PA26", 0, 26, {"gpio_in", "gpio_out", "gmac", NULL, "clk_out_c", NULL, "pa_eint26", NULL}, 6, 26}, {"PA27", 0, 27, {"gpio_in", "gpio_out", "gmac", NULL, NULL, NULL, "pa_eint27", NULL}, 6, 27}, {"PB0", 1, 0, {"gpio_in", "gpio_out", "i2s0", "uart3", NULL , NULL, "pb_eint0", NULL}, 6, 0}, {"PB1", 1, 1, {"gpio_in", "gpio_out", "i2s0", NULL, NULL, NULL, "pb_eint1", NULL}, 6, 1}, {"PB2", 1, 2, {"gpio_in", "gpio_out", "i2s0", NULL, NULL, NULL, "pb_eint2", NULL}, 6, 2}, {"PB3", 1, 3, {"gpio_in", "gpio_out", "i2s0", NULL, NULL, NULL, "pb_eint3", NULL}, 6, 3}, {"PB4", 1, 4, {"gpio_in", "gpio_out", "i2s0", "uart3", NULL, NULL, "pb_eint4", NULL}, 6, 4}, {"PB5", 1, 5, {"gpio_in", "gpio_out", "i2s0", "uart3", "i2c3", NULL, "pb_eint5", NULL}, 6, 5}, {"PB6", 1, 6, {"gpio_in", "gpio_out", "i2s0", "uart3", "i2c3", NULL, "pb_eint6", NULL}, 6, 6}, {"PB7", 1, 7, {"gpio_in", "gpio_out", "i2s0", NULL, NULL, NULL, "pb_eint7", NULL}, 6, 7}, {"PC0", 2, 0, {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}}, {"PC1", 2, 1, {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}}, {"PC2", 2, 2, {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}}, {"PC3", 2, 3, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC4", 2, 4, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC5", 2, 5, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC6", 2, 6, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC7", 2, 7, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC8", 2, 8, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC9", 2, 9, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC10", 2, 10, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC11", 2, 11, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC12", 2, 12, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC13", 2, 13, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC14", 2, 14, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC15", 2, 15, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC24", 2, 24, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, {"PC25", 2, 25, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC26", 2, 26, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC27", 2, 27, {"gpio_in", "gpio_out", NULL, "spi0",NULL, NULL, NULL, NULL}}, {"PD0", 3, 0, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD1", 3, 1, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD2", 3, 2, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD3", 3, 3, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD4", 3, 4, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD5", 3, 5, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD6", 3, 6, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD7", 3, 7, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD8", 3, 8, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD9", 3, 9, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD10", 3, 10, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD11", 3, 11, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD12", 3, 12, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD13", 3, 13, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD14", 3, 14, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD15", 3, 15, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD16", 3, 16, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD17", 3, 17, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD18", 3, 18, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD19", 3, 19, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD20", 3, 20, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD21", 3, 21, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD22", 3, 22, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD23", 3, 23, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD24", 3, 24, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD25", 3, 25, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD26", 3, 26, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD27", 3, 27, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PE0", 4, 0, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint0", NULL}, 6, 0}, {"PE1", 4, 1, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint1", NULL}, 6, 1}, {"PE2", 4, 2, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint2", NULL}, 6, 2}, {"PE3", 4, 3, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint3", NULL}, 6, 3}, {"PE4", 4, 4, {"gpio_in", "gpio_out", "csi", "uart5", NULL, NULL, "pe_eint4", NULL}, 6, 4}, {"PE5", 4, 5, {"gpio_in", "gpio_out", "csi", "uart5", NULL, NULL, "pe_eint5", NULL}, 6, 5}, {"PE6", 4, 6, {"gpio_in", "gpio_out", "csi", "uart5", NULL, NULL, "pe_eint6", NULL}, 6, 6}, {"PE7", 4, 7, {"gpio_in", "gpio_out", "csi", "uart5", NULL, NULL, "pe_eint7", NULL}, 6, 7}, {"PE8", 4, 8, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint8", NULL}, 6, 8}, {"PE9", 4, 9, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint9", NULL}, 6, 9}, {"PE10", 4, 10, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint10", NULL}, 6, 10}, {"PE11", 4, 11, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint11", NULL}, 6, 11}, {"PE12", 4, 12, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint12", NULL}, 6, 12}, {"PE13", 4, 13, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint13", NULL}, 6, 13}, {"PE14", 4, 14, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint14", NULL}, 6, 14}, {"PE15", 4, 15, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint15", NULL}, 6, 15}, {"PF0", 5, 0, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, {"PF1", 5, 1, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, {"PF2", 5, 2, {"gpio_in", "gpio_out", "mmc0", NULL, "uart0", NULL, NULL, NULL}}, {"PF3", 5, 3, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, {"PF4", 5, 4, {"gpio_in", "gpio_out", "mmc0", NULL, "uart0", NULL, NULL, NULL}}, {"PF5", 5, 5, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, {"PG0", 6, 0, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint0", NULL}, 6, 0}, {"PG1", 6, 1, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint1", NULL}, 6, 1}, {"PG2", 6, 2, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint2", NULL}, 6, 2}, {"PG3", 6, 3, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint3", NULL}, 6, 3}, {"PG4", 6, 4, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint4", NULL}, 6, 4}, {"PG5", 6, 5, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint5", NULL}, 6, 5}, {"PG6", 6, 6, {"gpio_in", "gpio_out", "uart2", NULL, NULL, NULL, "pg_eint6", NULL}, 6, 6}, {"PG7", 6, 7, {"gpio_in", "gpio_out", "uart2", NULL, NULL, NULL, "pg_eint7", NULL}, 6, 7}, {"PG8", 6, 8, {"gpio_in", "gpio_out", "uart2", NULL, NULL, NULL, "pg_eint8", NULL}, 6, 8}, {"PG9", 6, 9, {"gpio_in", "gpio_out", "uart2", NULL, NULL, NULL, "pg_eint9", NULL}, 6, 9}, {"PG10", 6, 10, {"gpio_in", "gpio_out", "i2c3", NULL, NULL, NULL, "pg_eint10", NULL}, 6, 10}, {"PG11", 6, 11, {"gpio_in", "gpio_out", "i2c3", NULL, NULL, NULL, "pg_eint11", NULL}, 6, 11}, {"PG12", 6, 12, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, "pg_eint12", NULL}, 6, 12}, {"PG13", 6, 13, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, "pg_eint13", NULL}, 6, 13}, {"PG14", 6, 14, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, "pg_eint14", NULL}, 6, 14}, {"PG15", 6, 15, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, "pg_eint15", NULL}, 6, 15}, {"PG16", 6, 16, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, "pg_eint16", NULL}, 6, 16}, {"PG17", 6, 17, {"gpio_in", "gpio_out", "uart4", NULL, NULL, NULL, "pg_eint17", NULL}, 6, 17}, {"PG18", 6, 18, {"gpio_in", "gpio_out", "uart4", NULL, NULL, NULL, "pg_eint18", NULL}, 6, 18}, {"PH9", 7, 9, {"gpio_in", "gpio_out", "spi2", "jtag", "pwm1", NULL, NULL, NULL}}, {"PH10", 7, 10, {"gpio_in", "gpio_out", "spi2", "jtag", "pwm1", NULL, NULL, NULL}}, {"PH11", 7, 11, {"gpio_in", "gpio_out", "spi2", "jtag", "pwm2", NULL, NULL, NULL}}, {"PH12", 7, 12, {"gpio_in", "gpio_out", "spi2", "jtag", "pwm2", NULL, NULL, NULL}}, {"PH13", 7, 13, {"gpio_in", "gpio_out", "pwm0", NULL, NULL, NULL, NULL, NULL}}, {"PH14", 7, 14, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}}, {"PH15", 7, 15, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}}, {"PH16", 7, 16, {"gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, NULL, NULL}}, {"PH17", 7, 17, {"gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, NULL, NULL}}, {"PH18", 7, 18, {"gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, NULL, NULL}}, {"PH19", 7, 19, {"gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, NULL, NULL}}, {"PH20", 7, 20, {"gpio_in", "gpio_out", "uart0", NULL, NULL, NULL, NULL, NULL}}, {"PH21", 7, 21, {"gpio_in", "gpio_out", "uart0", NULL, NULL, NULL, NULL, NULL}}, {"PH22", 7, 22, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, {"PH23", 7, 23, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, {"PH24", 7, 24, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, {"PH25", 7, 25, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, {"PH26", 7, 26, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, {"PH27", 7, 27, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, {"PH28", 7, 27, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, }; const struct allwinner_padconf a31s_padconf = { .npins = nitems(a31s_pins), .pins = a31s_pins, }; #endif /* SOC_ALLWINNER_A31S */ Index: head/sys/arm/allwinner/a33/a33_padconf.c =================================================================== --- head/sys/arm/allwinner/a33/a33_padconf.c (revision 355356) +++ head/sys/arm/allwinner/a33/a33_padconf.c (revision 355357) @@ -1,149 +1,148 @@ /*- * Copyright (c) 2016 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #ifdef SOC_ALLWINNER_A33 const static struct allwinner_pins a33_pins[] = { {"PB0", 1, 0, {"gpio_in", "gpio_out", "uart2", "uart0", "pb_eint0", NULL}, 4, 0}, {"PB1", 1, 1, {"gpio_in", "gpio_out", "uart2", "uart0", "pb_eint1", NULL}, 4, 1}, {"PB2", 1, 2, {"gpio_in", "gpio_out", "uart2", NULL, "pb_eint2", NULL}, 4, 2}, {"PB3", 1, 3, {"gpio_in", "gpio_out", "uart2", NULL, "pb_eint3", NULL}, 4, 3}, {"PB4", 1, 4, {"gpio_in", "gpio_out", "i2s0", "aif2", "pb_eint4", NULL}, 4, 4}, {"PB5", 1, 5, {"gpio_in", "gpio_out", "i2s0", "aif2", "pb_eint5", NULL}, 4, 5}, {"PB6", 1, 6, {"gpio_in", "gpio_out", "i2s0", "aif2", "pb_eint6", NULL}, 4, 6}, {"PB7", 1, 7, {"gpio_in", "gpio_out", "i2s0", "aif2", "pb_eint7", NULL}, 4, 7}, {"PC0", 2, 0, {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}}, {"PC1", 2, 1, {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}}, {"PC2", 2, 2, {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}}, {"PC3", 2, 3, {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}}, {"PC4", 2, 4, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC5", 2, 5, {"gpio_in", "gpio_out", "nand0", "mmc2", NULL, NULL, NULL, NULL}}, {"PC6", 2, 6, {"gpio_in", "gpio_out", "nand0", "mmc2", NULL, NULL, NULL, NULL}}, {"PC7", 2, 7, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, {"PC8", 2, 8, {"gpio_in", "gpio_out", "nand0", "mmc2", NULL, NULL, NULL, NULL}}, {"PC9", 2, 9, {"gpio_in", "gpio_out", "nand0", "mmc2", NULL, NULL, NULL, NULL}}, {"PC10", 2, 10, {"gpio_in", "gpio_out", "nand0", "mmc2", NULL, NULL, NULL, NULL}}, {"PC11", 2, 11, {"gpio_in", "gpio_out", "nand0", "mmc2", NULL, NULL, NULL, NULL}}, {"PC12", 2, 12, {"gpio_in", "gpio_out", "nand0", "mmc2", NULL, NULL, NULL, NULL}}, {"PC13", 2, 13, {"gpio_in", "gpio_out", "nand0", "mmc2", NULL, NULL, NULL, NULL}}, {"PC14", 2, 14, {"gpio_in", "gpio_out", "nand0", "mmc2", NULL, NULL, NULL, NULL}}, {"PC15", 2, 15, {"gpio_in", "gpio_out", "nand0", "mmc2", NULL, NULL, NULL, NULL}}, {"PC16", 2, 16, {"gpio_in", "gpio_out", "nand0", "mmc2", NULL, NULL, NULL, NULL}}, {"PD2", 3, 2, {"gpio_in", "gpio_out", "lcd0", "mmc1", NULL, NULL, NULL, NULL}}, {"PD3", 3, 3, {"gpio_in", "gpio_out", "lcd0", "mmc1", NULL, NULL, NULL, NULL}}, {"PD4", 3, 4, {"gpio_in", "gpio_out", "lcd0", "mmc1", NULL, NULL, NULL, NULL}}, {"PD5", 3, 5, {"gpio_in", "gpio_out", "lcd0", "mmc1", NULL, NULL, NULL, NULL}}, {"PD6", 3, 6, {"gpio_in", "gpio_out", "lcd0", "mmc1", NULL, NULL, NULL, NULL}}, {"PD7", 3, 7, {"gpio_in", "gpio_out", "lcd0", "mmc1", NULL, NULL, NULL, NULL}}, {"PD10", 3, 10, {"gpio_in", "gpio_out", "lcd0", "uart1", NULL, NULL, NULL, NULL}}, {"PD11", 3, 11, {"gpio_in", "gpio_out", "lcd0", "uart1", NULL, NULL, NULL, NULL}}, {"PD12", 3, 12, {"gpio_in", "gpio_out", "lcd0", "uart1", NULL, NULL, NULL, NULL}}, {"PD13", 3, 13, {"gpio_in", "gpio_out", "lcd0", "uart1", NULL, NULL, NULL, NULL}}, {"PD14", 3, 14, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD15", 3, 15, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, {"PD18", 3, 18, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD19", 3, 19, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD20", 3, 20, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD21", 3, 21, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD22", 3, 22, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD23", 3, 23, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD24", 3, 24, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD25", 3, 25, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD26", 3, 26, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PD27", 3, 27, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, {"PE0", 4, 0, {"gpio_in", "gpio_out", "csi", NULL, NULL, NULL, NULL, NULL}, 0, 0}, {"PE1", 4, 1, {"gpio_in", "gpio_out", "csi", NULL, NULL, NULL, NULL, NULL}, 0, 0}, {"PE2", 4, 2, {"gpio_in", "gpio_out", "csi", NULL, NULL, NULL, NULL, NULL}, 0, 0}, {"PE3", 4, 3, {"gpio_in", "gpio_out", "csi", NULL, NULL, NULL, NULL, NULL}, 0, 0}, {"PE4", 4, 4, {"gpio_in", "gpio_out", "csi", NULL, NULL, NULL, NULL, NULL}, 0, 0}, {"PE5", 4, 5, {"gpio_in", "gpio_out", "csi", NULL, NULL, NULL, NULL, NULL}, 0, 0}, {"PE6", 4, 6, {"gpio_in", "gpio_out", "csi", NULL, NULL, NULL, NULL, NULL}, 0, 0}, {"PE7", 4, 7, {"gpio_in", "gpio_out", "csi", NULL, NULL, NULL, NULL, NULL}, 0, 0}, {"PE8", 4, 8, {"gpio_in", "gpio_out", "csi", NULL, NULL, NULL, NULL, NULL}, 0, 0}, {"PE9", 4, 9, {"gpio_in", "gpio_out", "csi", NULL, NULL, NULL, NULL, NULL}, 0, 0}, {"PE10", 4, 10, {"gpio_in", "gpio_out", "csi", NULL, NULL, NULL, NULL, NULL}, 0, 0}, {"PE11", 4, 11, {"gpio_in", "gpio_out", "csi", NULL, NULL, NULL, NULL, NULL}, 0, 0}, {"PE12", 4, 12, {"gpio_in", "gpio_out", "csi", "i2c2", NULL, NULL, NULL, NULL}, 0, 0}, {"PE13", 4, 13, {"gpio_in", "gpio_out", "csi", "i2c2", NULL, NULL, NULL, NULL}, 0, 0}, {"PE14", 4, 14, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}, 0, 0}, {"PE15", 4, 15, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}, 0, 0}, {"PE16", 4, 16, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}, 0, 0}, {"PE17", 4, 16, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}, 0, 0}, {"PF0", 5, 0, {"gpio_in", "gpio_out", "mmc0", "jtag", NULL, NULL, NULL}}, {"PF1", 5, 1, {"gpio_in", "gpio_out", "mmc0", "jtag", NULL, NULL, NULL}}, {"PF2", 5, 2, {"gpio_in", "gpio_out", "mmc0", "uart0", NULL, NULL, NULL}}, {"PF3", 5, 3, {"gpio_in", "gpio_out", "mmc0", "jtag", NULL, NULL, NULL}}, {"PF4", 5, 4, {"gpio_in", "gpio_out", "mmc0", "uart0", NULL, NULL, NULL}}, {"PF5", 5, 5, {"gpio_in", "gpio_out", "mmc0", "jtag", NULL, NULL, NULL}}, {"PG0", 6, 0, {"gpio_in", "gpio_out", "mmc1", NULL, "pg_eint0", NULL}, 4, 0}, {"PG1", 6, 1, {"gpio_in", "gpio_out", "mmc1", NULL, "pg_eint1", NULL}, 4, 1}, {"PG2", 6, 2, {"gpio_in", "gpio_out", "mmc1", NULL, "pg_eint2", NULL}, 4, 2}, {"PG3", 6, 3, {"gpio_in", "gpio_out", "mmc1", NULL, "pg_eint3", NULL}, 4, 3}, {"PG4", 6, 4, {"gpio_in", "gpio_out", "mmc1", NULL, "pg_eint4", NULL}, 4, 4}, {"PG5", 6, 5, {"gpio_in", "gpio_out", "mmc1", NULL, "pg_eint5", NULL}, 4, 5}, {"PG6", 6, 6, {"gpio_in", "gpio_out", "uart1", NULL, "pg_eint6", NULL}, 4, 6}, {"PG7", 6, 7, {"gpio_in", "gpio_out", "uart1", NULL, "pg_eint7", NULL}, 4, 7}, {"PG8", 6, 8, {"gpio_in", "gpio_out", "uart1", NULL, "pg_eint8", NULL}, 4, 8}, {"PG9", 6, 9, {"gpio_in", "gpio_out", "uart1", NULL, "pg_eint9", NULL}, 4, 9}, {"PG10", 6, 10, {"gpio_in", "gpio_out", "i2s1", "aif3", "pg_eint10", NULL}, 4, 10}, {"PG11", 6, 11, {"gpio_in", "gpio_out", "i2s1", "aif3", "pg_eint11", NULL}, 4, 11}, {"PG12", 6, 12, {"gpio_in", "gpio_out", "i2s1", "aif3", "pg_eint12", NULL}, 4, 12}, {"PG13", 6, 13, {"gpio_in", "gpio_out", "i2s1", "aif3", "pg_eint13", NULL}, 4, 13}, {"PH0", 7, 0, {"gpio_in", "gpio_out", "pwm0", NULL, NULL, NULL, NULL, NULL}}, {"PH1", 7, 1, {"gpio_in", "gpio_out", "pwm1", NULL, NULL, NULL, NULL, NULL}}, {"PH2", 7, 2, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}}, {"PH3", 7, 3, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}}, {"PH4", 7, 4, {"gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, NULL, NULL}}, {"PH5", 7, 5, {"gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, NULL, NULL}}, {"PH6", 7, 6, {"gpio_in", "gpio_out", "spi0", "uart3", NULL, NULL, NULL, NULL}}, {"PH7", 7, 7, {"gpio_in", "gpio_out", "spi0", "uart3", NULL, NULL, NULL, NULL}}, {"PH8", 7, 8, {"gpio_in", "gpio_out", "spi0", "uart3", NULL, NULL, NULL, NULL}}, {"PH9", 7, 9, {"gpio_in", "gpio_out", "spi0", "uart3", NULL, NULL, NULL, NULL}}, }; const struct allwinner_padconf a33_padconf = { .npins = nitems(a33_pins), .pins = a33_pins, }; #endif /* SOC_ALLWINNER_A33 */ Index: head/sys/arm/allwinner/allwinner_pinctrl.h =================================================================== --- head/sys/arm/allwinner/allwinner_pinctrl.h (revision 355356) +++ head/sys/arm/allwinner/allwinner_pinctrl.h (revision 355357) @@ -1,48 +1,47 @@ /*- * Copyright (c) 2016 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _ALLWINNER_PINCTRL_H_ #define _ALLWINNER_PINCTRL_H_ #define AW_MAX_FUNC_BY_PIN 8 struct allwinner_pins { const char *name; uint8_t port; uint8_t pin; const char *functions[8]; uint8_t eint_func; uint8_t eint_num; }; struct allwinner_padconf { uint32_t npins; const struct allwinner_pins * pins; }; #endif /* _ALLWINNER_PINCTRL_H_ */ Index: head/sys/arm/allwinner/aw_machdep.h =================================================================== --- head/sys/arm/allwinner/aw_machdep.h (revision 355356) +++ head/sys/arm/allwinner/aw_machdep.h (revision 355357) @@ -1,52 +1,51 @@ /*- * Copyright (c) 2015 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ * */ #ifndef AW_MACHDEP_H #define AW_MACHDEP_H #define ALLWINNERSOC_A10 0x10000000 #define ALLWINNERSOC_A13 0x13000000 #define ALLWINNERSOC_A10S 0x10000001 #define ALLWINNERSOC_A20 0x20000000 #define ALLWINNERSOC_H3 0x30000000 #define ALLWINNERSOC_A31 0x31000000 #define ALLWINNERSOC_A31S 0x31000001 #define ALLWINNERSOC_A33 0x33000000 #define ALLWINNERSOC_A83T 0x83000000 #define ALLWINNERSOC_SUN4I 0x40000000 #define ALLWINNERSOC_SUN5I 0x50000000 #define ALLWINNERSOC_SUN6I 0x60000000 #define ALLWINNERSOC_SUN7I 0x70000000 #define ALLWINNERSOC_SUN8I 0x80000000 u_int allwinner_soc_type(void); u_int allwinner_soc_family(void); #endif /* AW_MACHDEP_H */ Index: head/sys/arm/allwinner/aw_mp.h =================================================================== --- head/sys/arm/allwinner/aw_mp.h (revision 355356) +++ head/sys/arm/allwinner/aw_mp.h (revision 355357) @@ -1,35 +1,34 @@ /*- * Copyright (c) 2016 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _AW_MP_H_ #define _AW_MP_H_ void aw_mp_setmaxid(platform_t plat); void aw_mp_start_ap(platform_t plat); void a83t_mp_start_ap(platform_t plat); #endif /* _AW_MP_H_ */ Index: head/sys/arm/allwinner/aw_nmi.c =================================================================== --- head/sys/arm/allwinner/aw_nmi.c (revision 355356) +++ head/sys/arm/allwinner/aw_nmi.c (revision 355357) @@ -1,421 +1,420 @@ /*- * Copyright (c) 2016 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pic_if.h" #define NMI_IRQ_CTRL_REG 0x0 #define NMI_IRQ_LOW_LEVEL 0x0 #define NMI_IRQ_LOW_EDGE 0x1 #define NMI_IRQ_HIGH_LEVEL 0x2 #define NMI_IRQ_HIGH_EDGE 0x3 #define NMI_IRQ_PENDING_REG 0x4 #define NMI_IRQ_ACK (1U << 0) #define A20_NMI_IRQ_ENABLE_REG 0x8 #define A31_NMI_IRQ_ENABLE_REG 0x34 #define NMI_IRQ_ENABLE (1U << 0) #define R_NMI_IRQ_CTRL_REG 0x0c #define R_NMI_IRQ_PENDING_REG 0x10 #define R_NMI_IRQ_ENABLE_REG 0x40 #define SC_NMI_READ(_sc, _reg) bus_read_4(_sc->res[0], _reg) #define SC_NMI_WRITE(_sc, _reg, _val) bus_write_4(_sc->res[0], _reg, _val) static struct resource_spec aw_nmi_res_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_IRQ, 0, RF_ACTIVE }, { -1, 0, 0 } }; struct aw_nmi_intr { struct intr_irqsrc isrc; u_int irq; enum intr_polarity pol; enum intr_trigger tri; }; struct aw_nmi_reg_cfg { uint8_t ctrl_reg; uint8_t pending_reg; uint8_t enable_reg; }; struct aw_nmi_softc { device_t dev; struct resource * res[2]; void * intrcookie; struct aw_nmi_intr intr; struct aw_nmi_reg_cfg * cfg; }; static struct aw_nmi_reg_cfg a20_nmi_cfg = { .ctrl_reg = NMI_IRQ_CTRL_REG, .pending_reg = NMI_IRQ_PENDING_REG, .enable_reg = A20_NMI_IRQ_ENABLE_REG, }; static struct aw_nmi_reg_cfg a31_nmi_cfg = { .ctrl_reg = NMI_IRQ_CTRL_REG, .pending_reg = NMI_IRQ_PENDING_REG, .enable_reg = A31_NMI_IRQ_ENABLE_REG, }; static struct aw_nmi_reg_cfg a83t_r_nmi_cfg = { .ctrl_reg = R_NMI_IRQ_CTRL_REG, .pending_reg = R_NMI_IRQ_PENDING_REG, .enable_reg = R_NMI_IRQ_ENABLE_REG, }; static struct ofw_compat_data compat_data[] = { {"allwinner,sun7i-a20-sc-nmi", (uintptr_t)&a20_nmi_cfg}, {"allwinner,sun6i-a31-sc-nmi", (uintptr_t)&a31_nmi_cfg}, {"allwinner,sun6i-a31-r-intc", (uintptr_t)&a83t_r_nmi_cfg}, {"allwinner,sun8i-a83t-r-intc", (uintptr_t)&a83t_r_nmi_cfg}, {NULL, 0}, }; static int aw_nmi_intr(void *arg) { struct aw_nmi_softc *sc; sc = arg; if (SC_NMI_READ(sc, sc->cfg->pending_reg) == 0) { device_printf(sc->dev, "Spurious interrupt\n"); return (FILTER_HANDLED); } if (intr_isrc_dispatch(&sc->intr.isrc, curthread->td_intr_frame) != 0) { SC_NMI_WRITE(sc, sc->cfg->enable_reg, !NMI_IRQ_ENABLE); device_printf(sc->dev, "Stray interrupt, NMI disabled\n"); } return (FILTER_HANDLED); } static void aw_nmi_enable_intr(device_t dev, struct intr_irqsrc *isrc) { struct aw_nmi_softc *sc; sc = device_get_softc(dev); SC_NMI_WRITE(sc, sc->cfg->enable_reg, NMI_IRQ_ENABLE); } static void aw_nmi_disable_intr(device_t dev, struct intr_irqsrc *isrc) { struct aw_nmi_softc *sc; sc = device_get_softc(dev); SC_NMI_WRITE(sc, sc->cfg->enable_reg, !NMI_IRQ_ENABLE); } static int aw_nmi_map_fdt(device_t dev, u_int ncells, pcell_t *cells, u_int *irqp, enum intr_polarity *polp, enum intr_trigger *trigp) { u_int irq, tripol; enum intr_polarity pol; enum intr_trigger trig; if (ncells != 2) { device_printf(dev, "Invalid #interrupt-cells\n"); return (EINVAL); } irq = cells[0]; if (irq != 0) { device_printf(dev, "Controller only support irq 0\n"); return (EINVAL); } tripol = cells[1]; switch (tripol) { case FDT_INTR_EDGE_RISING: trig = INTR_TRIGGER_EDGE; pol = INTR_POLARITY_HIGH; break; case FDT_INTR_EDGE_FALLING: trig = INTR_TRIGGER_EDGE; pol = INTR_POLARITY_LOW; break; case FDT_INTR_LEVEL_HIGH: trig = INTR_TRIGGER_LEVEL; pol = INTR_POLARITY_HIGH; break; case FDT_INTR_LEVEL_LOW: trig = INTR_TRIGGER_LEVEL; pol = INTR_POLARITY_LOW; break; default: device_printf(dev, "unsupported trigger/polarity 0x%2x\n", tripol); return (ENOTSUP); } *irqp = irq; if (polp != NULL) *polp = pol; if (trigp != NULL) *trigp = trig; return (0); } static int aw_nmi_map_intr(device_t dev, struct intr_map_data *data, struct intr_irqsrc **isrcp) { struct intr_map_data_fdt *daf; struct aw_nmi_softc *sc; int error; u_int irq; if (data->type != INTR_MAP_DATA_FDT) return (ENOTSUP); sc = device_get_softc(dev); daf = (struct intr_map_data_fdt *)data; error = aw_nmi_map_fdt(dev, daf->ncells, daf->cells, &irq, NULL, NULL); if (error == 0) *isrcp = &sc->intr.isrc; return (error); } static int aw_nmi_setup_intr(device_t dev, struct intr_irqsrc *isrc, struct resource *res, struct intr_map_data *data) { struct intr_map_data_fdt *daf; struct aw_nmi_softc *sc; struct aw_nmi_intr *nmi_intr; int error, icfg; u_int irq; enum intr_trigger trig; enum intr_polarity pol; /* Get config for interrupt. */ if (data == NULL || data->type != INTR_MAP_DATA_FDT) return (ENOTSUP); sc = device_get_softc(dev); nmi_intr = (struct aw_nmi_intr *)isrc; daf = (struct intr_map_data_fdt *)data; error = aw_nmi_map_fdt(dev, daf->ncells, daf->cells, &irq, &pol, &trig); if (error != 0) return (error); if (nmi_intr->irq != irq) return (EINVAL); /* Compare config if this is not first setup. */ if (isrc->isrc_handlers != 0) { if (pol != nmi_intr->pol || trig != nmi_intr->tri) return (EINVAL); else return (0); } nmi_intr->pol = pol; nmi_intr->tri = trig; if (trig == INTR_TRIGGER_LEVEL) { if (pol == INTR_POLARITY_LOW) icfg = NMI_IRQ_LOW_LEVEL; else icfg = NMI_IRQ_HIGH_LEVEL; } else { if (pol == INTR_POLARITY_HIGH) icfg = NMI_IRQ_HIGH_EDGE; else icfg = NMI_IRQ_LOW_EDGE; } SC_NMI_WRITE(sc, sc->cfg->ctrl_reg, icfg); return (0); } static int aw_nmi_teardown_intr(device_t dev, struct intr_irqsrc *isrc, struct resource *res, struct intr_map_data *data) { struct aw_nmi_softc *sc; sc = device_get_softc(dev); if (isrc->isrc_handlers == 0) { sc->intr.pol = INTR_POLARITY_CONFORM; sc->intr.tri = INTR_TRIGGER_CONFORM; SC_NMI_WRITE(sc, sc->cfg->enable_reg, !NMI_IRQ_ENABLE); } return (0); } static void aw_nmi_pre_ithread(device_t dev, struct intr_irqsrc *isrc) { struct aw_nmi_softc *sc; sc = device_get_softc(dev); aw_nmi_disable_intr(dev, isrc); SC_NMI_WRITE(sc, sc->cfg->pending_reg, NMI_IRQ_ACK); } static void aw_nmi_post_ithread(device_t dev, struct intr_irqsrc *isrc) { arm_irq_memory_barrier(0); aw_nmi_enable_intr(dev, isrc); } static void aw_nmi_post_filter(device_t dev, struct intr_irqsrc *isrc) { struct aw_nmi_softc *sc; sc = device_get_softc(dev); arm_irq_memory_barrier(0); SC_NMI_WRITE(sc, sc->cfg->pending_reg, NMI_IRQ_ACK); } static int aw_nmi_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Allwinner NMI Controller"); return (BUS_PROBE_DEFAULT); } static int aw_nmi_attach(device_t dev) { struct aw_nmi_softc *sc; phandle_t xref; sc = device_get_softc(dev); sc->dev = dev; sc->cfg = (struct aw_nmi_reg_cfg *) ofw_bus_search_compatible(dev, compat_data)->ocd_data; if (bus_alloc_resources(dev, aw_nmi_res_spec, sc->res) != 0) { device_printf(dev, "can't allocate device resources\n"); return (ENXIO); } if ((bus_setup_intr(dev, sc->res[1], INTR_TYPE_MISC, aw_nmi_intr, NULL, sc, &sc->intrcookie))) { device_printf(dev, "unable to register interrupt handler\n"); bus_release_resources(dev, aw_nmi_res_spec, sc->res); return (ENXIO); } /* Disable and clear interrupts */ SC_NMI_WRITE(sc, sc->cfg->enable_reg, !NMI_IRQ_ENABLE); SC_NMI_WRITE(sc, sc->cfg->pending_reg, NMI_IRQ_ACK); xref = OF_xref_from_node(ofw_bus_get_node(dev)); /* Register our isrc */ sc->intr.irq = 0; sc->intr.pol = INTR_POLARITY_CONFORM; sc->intr.tri = INTR_TRIGGER_CONFORM; if (intr_isrc_register(&sc->intr.isrc, sc->dev, 0, "%s,%u", device_get_nameunit(sc->dev), sc->intr.irq) != 0) goto error; if (intr_pic_register(dev, (intptr_t)xref) == NULL) { device_printf(dev, "could not register pic\n"); goto error; } return (0); error: bus_teardown_intr(dev, sc->res[1], sc->intrcookie); bus_release_resources(dev, aw_nmi_res_spec, sc->res); return (ENXIO); } static device_method_t aw_nmi_methods[] = { DEVMETHOD(device_probe, aw_nmi_probe), DEVMETHOD(device_attach, aw_nmi_attach), /* Interrupt controller interface */ DEVMETHOD(pic_disable_intr, aw_nmi_disable_intr), DEVMETHOD(pic_enable_intr, aw_nmi_enable_intr), DEVMETHOD(pic_map_intr, aw_nmi_map_intr), DEVMETHOD(pic_setup_intr, aw_nmi_setup_intr), DEVMETHOD(pic_teardown_intr, aw_nmi_teardown_intr), DEVMETHOD(pic_post_filter, aw_nmi_post_filter), DEVMETHOD(pic_post_ithread, aw_nmi_post_ithread), DEVMETHOD(pic_pre_ithread, aw_nmi_pre_ithread), {0, 0}, }; static driver_t aw_nmi_driver = { "aw_nmi", aw_nmi_methods, sizeof(struct aw_nmi_softc), }; static devclass_t aw_nmi_devclass; EARLY_DRIVER_MODULE(aw_nmi, simplebus, aw_nmi_driver, aw_nmi_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE); Index: head/sys/arm/allwinner/aw_ts.c =================================================================== --- head/sys/arm/allwinner/aw_ts.c (revision 355356) +++ head/sys/arm/allwinner/aw_ts.c (revision 355357) @@ -1,229 +1,228 @@ /*- * Copyright (c) 2016 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Allwinner Touch Sreen driver * Touch screen part is not done, only the thermal sensor part is. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #define READ(_sc, _r) bus_read_4((_sc)->res[0], (_r)) #define WRITE(_sc, _r, _v) bus_write_4((_sc)->res[0], (_r), (_v)) /* Control register 0 */ #define TP_CTRL0 0x00 #define TP_CTRL0_TACQ(x) ((x & 0xFF) << 0) #define TP_CTRL0_FS_DIV(x) ((x & 0xF) << 16) #define TP_CTRL0_CLK_DIV(x) ((x & 0x3) << 20) #define TP_CTRL0_CLK_SELECT(x) ((x & 0x1) << 22) /* Control register 1 */ #define TP_CTRL1 0x04 #define TP_CTRL1_MODE_EN (1 << 4) /* Control register 2 */ #define TP_CTRL2 0x08 /* Control register 3 */ #define TP_CTRL3 0x0C /* Int/FIFO control register */ #define TP_FIFOC 0x10 #define TP_FIFOC_TEMP_IRQ_ENABLE (1 << 18) /* Int/FIFO status register */ #define TP_FIFOS 0x14 #define TP_FIFOS_TEMP_IRQ_PENDING (1 << 18) /* Temperature Period Register */ #define TP_TPR 0x18 #define TP_TPR_TEMP_EN (1 << 16) #define TP_TPR_TEMP_PERIOD(x) (x << 0) /* Common data register */ #define TP_CDAT 0x1C /* Temperature data register */ #define TEMP_DATA 0x20 /* TP Data register*/ #define TP_DATA 0x24 /* TP IO config register */ #define TP_IO_CONFIG 0x28 /* TP IO port data register */ #define TP_IO_DATA 0x2C struct aw_ts_softc { device_t dev; struct resource * res[2]; void * intrhand; int temp_data; int temp_offset; int temp_step; }; static struct resource_spec aw_ts_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, { -1, 0 } }; #define A10_TS 1 #define A13_TS 2 #define AW_TS_TEMP_SYSCTL 1 static struct ofw_compat_data compat_data[] = { {"allwinner,sun4i-a10-ts", A10_TS}, {"allwinner,sun5i-a13-ts", A13_TS}, {NULL, 0} }; static void aw_ts_intr(void *arg) { struct aw_ts_softc *sc; int val; sc= (struct aw_ts_softc *)arg; val = READ(sc, TP_FIFOS); if (val & TP_FIFOS_TEMP_IRQ_PENDING) { /* Convert the value to millicelsius then millikelvin */ sc->temp_data = (READ(sc, TEMP_DATA) * sc->temp_step - sc->temp_offset) + 273150; } WRITE(sc, TP_FIFOS, val); } static int aw_ts_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Allwinner Touch Screen controller"); return (BUS_PROBE_DEFAULT); } static int aw_ts_attach(device_t dev) { struct aw_ts_softc *sc; sc = device_get_softc(dev); sc->dev = dev; if (bus_alloc_resources(dev, aw_ts_spec, sc->res) != 0) { device_printf(dev, "could not allocate memory resource\n"); return (ENXIO); } if (bus_setup_intr(dev, sc->res[1], INTR_TYPE_MISC | INTR_MPSAFE, NULL, aw_ts_intr, sc, &sc->intrhand)) { bus_release_resources(dev, aw_ts_spec, sc->res); device_printf(dev, "cannot setup interrupt handler\n"); return (ENXIO); } /* * Thoses magic values were taken from linux which take them from * the allwinner SDK or found them by deduction */ switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) { case A10_TS: sc->temp_offset = 257000; sc->temp_step = 133; break; case A13_TS: sc->temp_offset = 144700; sc->temp_step = 100; break; } /* Enable clock and set divisers */ WRITE(sc, TP_CTRL0, TP_CTRL0_CLK_SELECT(0) | TP_CTRL0_CLK_DIV(2) | TP_CTRL0_FS_DIV(7) | TP_CTRL0_TACQ(63)); /* Enable TS module */ WRITE(sc, TP_CTRL1, TP_CTRL1_MODE_EN); /* Enable Temperature, period is ~2s */ WRITE(sc, TP_TPR, TP_TPR_TEMP_EN | TP_TPR_TEMP_PERIOD(1953)); /* Enable temp irq */ WRITE(sc, TP_FIFOC, TP_FIFOC_TEMP_IRQ_ENABLE); /* Add sysctl */ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, &sc->temp_data, 0, sysctl_handle_int, "IK3", "CPU Temperature"); return (0); } static device_method_t aw_ts_methods[] = { DEVMETHOD(device_probe, aw_ts_probe), DEVMETHOD(device_attach, aw_ts_attach), DEVMETHOD_END }; static driver_t aw_ts_driver = { "aw_ts", aw_ts_methods, sizeof(struct aw_ts_softc), }; static devclass_t aw_ts_devclass; DRIVER_MODULE(aw_ts, simplebus, aw_ts_driver, aw_ts_devclass, 0, 0); Index: head/sys/arm/allwinner/axp209.c =================================================================== --- head/sys/arm/allwinner/axp209.c (revision 355356) +++ head/sys/arm/allwinner/axp209.c (revision 355357) @@ -1,1409 +1,1408 @@ /*- * Copyright (c) 2015-2016 Emmanuel Vadot * Copyright (c) 2016 Jared McNeill - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * X-Power AXP209/AXP211 PMU for Allwinner SoCs */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gpio_if.h" #include "regdev_if.h" MALLOC_DEFINE(M_AXP2XX_REG, "Axp2XX regulator", "Axp2XX power regulator"); struct axp2xx_regdef { intptr_t id; char *name; uint8_t enable_reg; uint8_t enable_mask; uint8_t voltage_reg; uint8_t voltage_mask; uint8_t voltage_shift; int voltage_min; int voltage_max; int voltage_step; int voltage_nstep; }; static struct axp2xx_regdef axp209_regdefs[] = { { .id = AXP209_REG_ID_DCDC2, .name = "dcdc2", .enable_reg = AXP209_POWERCTL, .enable_mask = AXP209_POWERCTL_DCDC2, .voltage_reg = AXP209_REG_DCDC2_VOLTAGE, .voltage_mask = 0x3f, .voltage_min = 700, .voltage_max = 2275, .voltage_step = 25, .voltage_nstep = 64, }, { .id = AXP209_REG_ID_DCDC3, .name = "dcdc3", .enable_reg = AXP209_POWERCTL, .enable_mask = AXP209_POWERCTL_DCDC3, .voltage_reg = AXP209_REG_DCDC3_VOLTAGE, .voltage_mask = 0x7f, .voltage_min = 700, .voltage_max = 3500, .voltage_step = 25, .voltage_nstep = 128, }, { .id = AXP209_REG_ID_LDO2, .name = "ldo2", .enable_reg = AXP209_POWERCTL, .enable_mask = AXP209_POWERCTL_LDO2, .voltage_reg = AXP209_REG_LDO24_VOLTAGE, .voltage_mask = 0xf0, .voltage_shift = 4, .voltage_min = 1800, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 16, }, { .id = AXP209_REG_ID_LDO3, .name = "ldo3", .enable_reg = AXP209_POWERCTL, .enable_mask = AXP209_POWERCTL_LDO3, .voltage_reg = AXP209_REG_LDO3_VOLTAGE, .voltage_mask = 0x7f, .voltage_min = 700, .voltage_max = 2275, .voltage_step = 25, .voltage_nstep = 128, }, }; static struct axp2xx_regdef axp221_regdefs[] = { { .id = AXP221_REG_ID_DLDO1, .name = "dldo1", .enable_reg = AXP221_POWERCTL_2, .enable_mask = AXP221_POWERCTL2_DLDO1, .voltage_reg = AXP221_REG_DLDO1_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 700, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 26, }, { .id = AXP221_REG_ID_DLDO2, .name = "dldo2", .enable_reg = AXP221_POWERCTL_2, .enable_mask = AXP221_POWERCTL2_DLDO2, .voltage_reg = AXP221_REG_DLDO2_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 700, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 26, }, { .id = AXP221_REG_ID_DLDO3, .name = "dldo3", .enable_reg = AXP221_POWERCTL_2, .enable_mask = AXP221_POWERCTL2_DLDO3, .voltage_reg = AXP221_REG_DLDO3_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 700, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 26, }, { .id = AXP221_REG_ID_DLDO4, .name = "dldo4", .enable_reg = AXP221_POWERCTL_2, .enable_mask = AXP221_POWERCTL2_DLDO4, .voltage_reg = AXP221_REG_DLDO4_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 700, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 26, }, { .id = AXP221_REG_ID_ELDO1, .name = "eldo1", .enable_reg = AXP221_POWERCTL_2, .enable_mask = AXP221_POWERCTL2_ELDO1, .voltage_reg = AXP221_REG_ELDO1_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 700, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 26, }, { .id = AXP221_REG_ID_ELDO2, .name = "eldo2", .enable_reg = AXP221_POWERCTL_2, .enable_mask = AXP221_POWERCTL2_ELDO2, .voltage_reg = AXP221_REG_ELDO2_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 700, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 26, }, { .id = AXP221_REG_ID_ELDO3, .name = "eldo3", .enable_reg = AXP221_POWERCTL_2, .enable_mask = AXP221_POWERCTL2_ELDO3, .voltage_reg = AXP221_REG_ELDO3_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 700, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 26, }, { .id = AXP221_REG_ID_DC5LDO, .name = "dc5ldo", .enable_reg = AXP221_POWERCTL_1, .enable_mask = AXP221_POWERCTL1_DC5LDO, .voltage_reg = AXP221_REG_DC5LDO_VOLTAGE, .voltage_mask = 0x3, .voltage_min = 700, .voltage_max = 1400, .voltage_step = 100, .voltage_nstep = 7, }, { .id = AXP221_REG_ID_DCDC1, .name = "dcdc1", .enable_reg = AXP221_POWERCTL_1, .enable_mask = AXP221_POWERCTL1_DCDC1, .voltage_reg = AXP221_REG_DCDC1_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 1600, .voltage_max = 3400, .voltage_step = 100, .voltage_nstep = 18, }, { .id = AXP221_REG_ID_DCDC2, .name = "dcdc2", .enable_reg = AXP221_POWERCTL_1, .enable_mask = AXP221_POWERCTL1_DCDC2, .voltage_reg = AXP221_REG_DCDC2_VOLTAGE, .voltage_mask = 0x3f, .voltage_min = 600, .voltage_max = 1540, .voltage_step = 20, .voltage_nstep = 47, }, { .id = AXP221_REG_ID_DCDC3, .name = "dcdc3", .enable_reg = AXP221_POWERCTL_1, .enable_mask = AXP221_POWERCTL1_DCDC3, .voltage_reg = AXP221_REG_DCDC3_VOLTAGE, .voltage_mask = 0x3f, .voltage_min = 600, .voltage_max = 1860, .voltage_step = 20, .voltage_nstep = 63, }, { .id = AXP221_REG_ID_DCDC4, .name = "dcdc4", .enable_reg = AXP221_POWERCTL_1, .enable_mask = AXP221_POWERCTL1_DCDC4, .voltage_reg = AXP221_REG_DCDC4_VOLTAGE, .voltage_mask = 0x3f, .voltage_min = 600, .voltage_max = 1540, .voltage_step = 20, .voltage_nstep = 47, }, { .id = AXP221_REG_ID_DCDC5, .name = "dcdc5", .enable_reg = AXP221_POWERCTL_1, .enable_mask = AXP221_POWERCTL1_DCDC5, .voltage_reg = AXP221_REG_DCDC5_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 1000, .voltage_max = 2550, .voltage_step = 50, .voltage_nstep = 31, }, { .id = AXP221_REG_ID_ALDO1, .name = "aldo1", .enable_reg = AXP221_POWERCTL_1, .enable_mask = AXP221_POWERCTL1_ALDO1, .voltage_reg = AXP221_REG_ALDO1_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 700, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 26, }, { .id = AXP221_REG_ID_ALDO2, .name = "aldo2", .enable_reg = AXP221_POWERCTL_1, .enable_mask = AXP221_POWERCTL1_ALDO2, .voltage_reg = AXP221_REG_ALDO2_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 700, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 26, }, { .id = AXP221_REG_ID_ALDO3, .name = "aldo3", .enable_reg = AXP221_POWERCTL_3, .enable_mask = AXP221_POWERCTL3_ALDO3, .voltage_reg = AXP221_REG_ALDO3_VOLTAGE, .voltage_mask = 0x1f, .voltage_min = 700, .voltage_max = 3300, .voltage_step = 100, .voltage_nstep = 26, }, { .id = AXP221_REG_ID_DC1SW, .name = "dc1sw", .enable_reg = AXP221_POWERCTL_2, .enable_mask = AXP221_POWERCTL2_DC1SW, }, }; struct axp2xx_reg_sc { struct regnode *regnode; device_t base_dev; struct axp2xx_regdef *def; phandle_t xref; struct regnode_std_param *param; }; struct axp2xx_pins { const char *name; uint8_t ctrl_reg; uint8_t status_reg; uint8_t status_mask; uint8_t status_shift; }; /* GPIO3 is different, don't expose it for now */ static const struct axp2xx_pins axp209_pins[] = { { .name = "GPIO0", .ctrl_reg = AXP2XX_GPIO0_CTRL, .status_reg = AXP2XX_GPIO_STATUS, .status_mask = 0x10, .status_shift = 4, }, { .name = "GPIO1", .ctrl_reg = AXP2XX_GPIO1_CTRL, .status_reg = AXP2XX_GPIO_STATUS, .status_mask = 0x20, .status_shift = 5, }, { .name = "GPIO2", .ctrl_reg = AXP209_GPIO2_CTRL, .status_reg = AXP2XX_GPIO_STATUS, .status_mask = 0x40, .status_shift = 6, }, }; static const struct axp2xx_pins axp221_pins[] = { { .name = "GPIO0", .ctrl_reg = AXP2XX_GPIO0_CTRL, .status_reg = AXP2XX_GPIO_STATUS, .status_mask = 0x1, .status_shift = 0x0, }, { .name = "GPIO1", .ctrl_reg = AXP2XX_GPIO0_CTRL, .status_reg = AXP2XX_GPIO_STATUS, .status_mask = 0x2, .status_shift = 0x1, }, }; struct axp2xx_sensors { int id; const char *name; const char *desc; const char *format; uint8_t enable_reg; uint8_t enable_mask; uint8_t value_reg; uint8_t value_size; uint8_t h_value_mask; uint8_t h_value_shift; uint8_t l_value_mask; uint8_t l_value_shift; int value_step; int value_convert; }; static const struct axp2xx_sensors axp209_sensors[] = { { .id = AXP209_ACVOLT, .name = "acvolt", .desc = "AC Voltage (microvolt)", .format = "I", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP209_ADC1_ACVOLT, .value_reg = AXP209_ACIN_VOLTAGE, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 4, .l_value_mask = 0xf, .l_value_shift = 0, .value_step = AXP209_VOLT_STEP, }, { .id = AXP209_ACCURRENT, .name = "accurrent", .desc = "AC Current (microAmpere)", .format = "I", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP209_ADC1_ACCURRENT, .value_reg = AXP209_ACIN_CURRENT, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 4, .l_value_mask = 0xf, .l_value_shift = 0, .value_step = AXP209_ACCURRENT_STEP, }, { .id = AXP209_VBUSVOLT, .name = "vbusvolt", .desc = "VBUS Voltage (microVolt)", .format = "I", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP209_ADC1_VBUSVOLT, .value_reg = AXP209_VBUS_VOLTAGE, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 4, .l_value_mask = 0xf, .l_value_shift = 0, .value_step = AXP209_VOLT_STEP, }, { .id = AXP209_VBUSCURRENT, .name = "vbuscurrent", .desc = "VBUS Current (microAmpere)", .format = "I", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP209_ADC1_VBUSCURRENT, .value_reg = AXP209_VBUS_CURRENT, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 4, .l_value_mask = 0xf, .l_value_shift = 0, .value_step = AXP209_VBUSCURRENT_STEP, }, { .id = AXP2XX_BATVOLT, .name = "batvolt", .desc = "Battery Voltage (microVolt)", .format = "I", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP2XX_ADC1_BATVOLT, .value_reg = AXP2XX_BAT_VOLTAGE, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 4, .l_value_mask = 0xf, .l_value_shift = 0, .value_step = AXP2XX_BATVOLT_STEP, }, { .id = AXP2XX_BATCHARGECURRENT, .name = "batchargecurrent", .desc = "Battery Charging Current (microAmpere)", .format = "I", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP2XX_ADC1_BATCURRENT, .value_reg = AXP2XX_BAT_CHARGE_CURRENT, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 5, .l_value_mask = 0x1f, .l_value_shift = 0, .value_step = AXP2XX_BATCURRENT_STEP, }, { .id = AXP2XX_BATDISCHARGECURRENT, .name = "batdischargecurrent", .desc = "Battery Discharging Current (microAmpere)", .format = "I", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP2XX_ADC1_BATCURRENT, .value_reg = AXP2XX_BAT_DISCHARGE_CURRENT, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 5, .l_value_mask = 0x1f, .l_value_shift = 0, .value_step = AXP2XX_BATCURRENT_STEP, }, { .id = AXP2XX_TEMP, .name = "temp", .desc = "Internal Temperature", .format = "IK", .enable_reg = AXP209_ADC_ENABLE2, .enable_mask = AXP209_ADC2_TEMP, .value_reg = AXP209_TEMPMON, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 4, .l_value_mask = 0xf, .l_value_shift = 0, .value_step = 1, .value_convert = -(AXP209_TEMPMON_MIN - AXP209_0C_TO_K), }, }; static const struct axp2xx_sensors axp221_sensors[] = { { .id = AXP2XX_BATVOLT, .name = "batvolt", .desc = "Battery Voltage (microVolt)", .format = "I", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP2XX_ADC1_BATVOLT, .value_reg = AXP2XX_BAT_VOLTAGE, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 4, .l_value_mask = 0xf, .l_value_shift = 0, .value_step = AXP2XX_BATVOLT_STEP, }, { .id = AXP2XX_BATCHARGECURRENT, .name = "batchargecurrent", .desc = "Battery Charging Current (microAmpere)", .format = "I", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP2XX_ADC1_BATCURRENT, .value_reg = AXP2XX_BAT_CHARGE_CURRENT, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 5, .l_value_mask = 0x1f, .l_value_shift = 0, .value_step = AXP2XX_BATCURRENT_STEP, }, { .id = AXP2XX_BATDISCHARGECURRENT, .name = "batdischargecurrent", .desc = "Battery Discharging Current (microAmpere)", .format = "I", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP2XX_ADC1_BATCURRENT, .value_reg = AXP2XX_BAT_DISCHARGE_CURRENT, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 5, .l_value_mask = 0x1f, .l_value_shift = 0, .value_step = AXP2XX_BATCURRENT_STEP, }, { .id = AXP2XX_TEMP, .name = "temp", .desc = "Internal Temperature", .format = "IK", .enable_reg = AXP2XX_ADC_ENABLE1, .enable_mask = AXP221_ADC1_TEMP, .value_reg = AXP221_TEMPMON, .value_size = 2, .h_value_mask = 0xff, .h_value_shift = 4, .l_value_mask = 0xf, .l_value_shift = 0, .value_step = 1, .value_convert = -(AXP221_TEMPMON_MIN - AXP209_0C_TO_K), }, }; enum AXP2XX_TYPE { AXP209 = 1, AXP221, }; struct axp2xx_softc { device_t dev; struct resource * res[1]; void * intrcookie; struct intr_config_hook intr_hook; struct mtx mtx; uint8_t type; /* GPIO */ device_t gpiodev; int npins; const struct axp2xx_pins *pins; /* Sensors */ const struct axp2xx_sensors *sensors; int nsensors; /* Regulators */ struct axp2xx_reg_sc **regs; int nregs; struct axp2xx_regdef *regdefs; }; static struct ofw_compat_data compat_data[] = { { "x-powers,axp209", AXP209 }, { "x-powers,axp221", AXP221 }, { NULL, 0 } }; static struct resource_spec axp_res_spec[] = { { SYS_RES_IRQ, 0, RF_ACTIVE }, { -1, 0, 0 } }; #define AXP_LOCK(sc) mtx_lock(&(sc)->mtx) #define AXP_UNLOCK(sc) mtx_unlock(&(sc)->mtx) static int axp2xx_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size) { return (iicdev_readfrom(dev, reg, data, size, IIC_INTRWAIT)); } static int axp2xx_write(device_t dev, uint8_t reg, uint8_t data) { return (iicdev_writeto(dev, reg, &data, sizeof(data), IIC_INTRWAIT)); } static int axp2xx_regnode_init(struct regnode *regnode) { return (0); } static int axp2xx_regnode_enable(struct regnode *regnode, bool enable, int *udelay) { struct axp2xx_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); axp2xx_read(sc->base_dev, sc->def->enable_reg, &val, 1); if (enable) val |= sc->def->enable_mask; else val &= ~sc->def->enable_mask; axp2xx_write(sc->base_dev, sc->def->enable_reg, val); *udelay = 0; return (0); } static void axp2xx_regnode_reg_to_voltage(struct axp2xx_reg_sc *sc, uint8_t val, int *uv) { if (val < sc->def->voltage_nstep) *uv = sc->def->voltage_min + val * sc->def->voltage_step; else *uv = sc->def->voltage_min + (sc->def->voltage_nstep * sc->def->voltage_step); *uv *= 1000; } static int axp2xx_regnode_voltage_to_reg(struct axp2xx_reg_sc *sc, int min_uvolt, int max_uvolt, uint8_t *val) { uint8_t nval; int nstep, uvolt; nval = 0; uvolt = sc->def->voltage_min * 1000; for (nstep = 0; nstep < sc->def->voltage_nstep && uvolt < min_uvolt; nstep++) { ++nval; uvolt += (sc->def->voltage_step * 1000); } if (uvolt > max_uvolt) return (EINVAL); *val = nval; return (0); } static int axp2xx_regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay) { struct axp2xx_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); if (!sc->def->voltage_step) return (ENXIO); if (axp2xx_regnode_voltage_to_reg(sc, min_uvolt, max_uvolt, &val) != 0) return (ERANGE); axp2xx_write(sc->base_dev, sc->def->voltage_reg, val); *udelay = 0; return (0); } static int axp2xx_regnode_get_voltage(struct regnode *regnode, int *uvolt) { struct axp2xx_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); if (!sc->def->voltage_step) return (ENXIO); axp2xx_read(sc->base_dev, sc->def->voltage_reg, &val, 1); axp2xx_regnode_reg_to_voltage(sc, val & sc->def->voltage_mask, uvolt); return (0); } static regnode_method_t axp2xx_regnode_methods[] = { /* Regulator interface */ REGNODEMETHOD(regnode_init, axp2xx_regnode_init), REGNODEMETHOD(regnode_enable, axp2xx_regnode_enable), REGNODEMETHOD(regnode_set_voltage, axp2xx_regnode_set_voltage), REGNODEMETHOD(regnode_get_voltage, axp2xx_regnode_get_voltage), REGNODEMETHOD(regnode_check_voltage, regnode_method_check_voltage), REGNODEMETHOD_END }; DEFINE_CLASS_1(axp2xx_regnode, axp2xx_regnode_class, axp2xx_regnode_methods, sizeof(struct axp2xx_reg_sc), regnode_class); static int axp2xx_sysctl(SYSCTL_HANDLER_ARGS) { struct axp2xx_softc *sc; device_t dev = arg1; enum axp2xx_sensor sensor = arg2; uint8_t data[2]; int val, error, i, found; sc = device_get_softc(dev); for (found = 0, i = 0; i < sc->nsensors; i++) { if (sc->sensors[i].id == sensor) { found = 1; break; } } if (found == 0) return (ENOENT); error = axp2xx_read(dev, sc->sensors[i].value_reg, data, 2); if (error != 0) return (error); val = ((data[0] & sc->sensors[i].h_value_mask) << sc->sensors[i].h_value_shift); val |= ((data[1] & sc->sensors[i].l_value_mask) << sc->sensors[i].l_value_shift); val *= sc->sensors[i].value_step; val += sc->sensors[i].value_convert; return sysctl_handle_opaque(oidp, &val, sizeof(val), req); } static void axp2xx_shutdown(void *devp, int howto) { device_t dev; if (!(howto & RB_POWEROFF)) return; dev = (device_t)devp; if (bootverbose) device_printf(dev, "Shutdown AXP2xx\n"); axp2xx_write(dev, AXP2XX_SHUTBAT, AXP2XX_SHUTBAT_SHUTDOWN); } static void axp2xx_intr(void *arg) { struct axp2xx_softc *sc; uint8_t reg; sc = arg; axp2xx_read(sc->dev, AXP2XX_IRQ1_STATUS, ®, 1); if (reg) { if (reg & AXP2XX_IRQ1_AC_OVERVOLT) devctl_notify("PMU", "AC", "overvoltage", NULL); if (reg & AXP2XX_IRQ1_VBUS_OVERVOLT) devctl_notify("PMU", "USB", "overvoltage", NULL); if (reg & AXP2XX_IRQ1_VBUS_LOW) devctl_notify("PMU", "USB", "undervoltage", NULL); if (reg & AXP2XX_IRQ1_AC_CONN) devctl_notify("PMU", "AC", "plugged", NULL); if (reg & AXP2XX_IRQ1_AC_DISCONN) devctl_notify("PMU", "AC", "unplugged", NULL); if (reg & AXP2XX_IRQ1_VBUS_CONN) devctl_notify("PMU", "USB", "plugged", NULL); if (reg & AXP2XX_IRQ1_VBUS_DISCONN) devctl_notify("PMU", "USB", "unplugged", NULL); axp2xx_write(sc->dev, AXP2XX_IRQ1_STATUS, AXP2XX_IRQ_ACK); } axp2xx_read(sc->dev, AXP2XX_IRQ2_STATUS, ®, 1); if (reg) { if (reg & AXP2XX_IRQ2_BATT_CHARGED) devctl_notify("PMU", "Battery", "charged", NULL); if (reg & AXP2XX_IRQ2_BATT_CHARGING) devctl_notify("PMU", "Battery", "charging", NULL); if (reg & AXP2XX_IRQ2_BATT_CONN) devctl_notify("PMU", "Battery", "connected", NULL); if (reg & AXP2XX_IRQ2_BATT_DISCONN) devctl_notify("PMU", "Battery", "disconnected", NULL); if (reg & AXP2XX_IRQ2_BATT_TEMP_LOW) devctl_notify("PMU", "Battery", "low temp", NULL); if (reg & AXP2XX_IRQ2_BATT_TEMP_OVER) devctl_notify("PMU", "Battery", "high temp", NULL); axp2xx_write(sc->dev, AXP2XX_IRQ2_STATUS, AXP2XX_IRQ_ACK); } axp2xx_read(sc->dev, AXP2XX_IRQ3_STATUS, ®, 1); if (reg) { if (reg & AXP2XX_IRQ3_PEK_SHORT) shutdown_nice(RB_POWEROFF); axp2xx_write(sc->dev, AXP2XX_IRQ3_STATUS, AXP2XX_IRQ_ACK); } axp2xx_read(sc->dev, AXP2XX_IRQ4_STATUS, ®, 1); if (reg) { axp2xx_write(sc->dev, AXP2XX_IRQ4_STATUS, AXP2XX_IRQ_ACK); } axp2xx_read(sc->dev, AXP2XX_IRQ5_STATUS, ®, 1); if (reg) { axp2xx_write(sc->dev, AXP2XX_IRQ5_STATUS, AXP2XX_IRQ_ACK); } } static device_t axp2xx_gpio_get_bus(device_t dev) { struct axp2xx_softc *sc; sc = device_get_softc(dev); return (sc->gpiodev); } static int axp2xx_gpio_pin_max(device_t dev, int *maxpin) { struct axp2xx_softc *sc; sc = device_get_softc(dev); *maxpin = sc->npins - 1; return (0); } static int axp2xx_gpio_pin_getname(device_t dev, uint32_t pin, char *name) { struct axp2xx_softc *sc; sc = device_get_softc(dev); if (pin >= sc->npins) return (EINVAL); snprintf(name, GPIOMAXNAME, "%s", axp209_pins[pin].name); return (0); } static int axp2xx_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) { struct axp2xx_softc *sc; sc = device_get_softc(dev); if (pin >= sc->npins) return (EINVAL); *caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT; return (0); } static int axp2xx_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) { struct axp2xx_softc *sc; uint8_t data, func; int error; sc = device_get_softc(dev); if (pin >= sc->npins) return (EINVAL); AXP_LOCK(sc); error = axp2xx_read(dev, sc->pins[pin].ctrl_reg, &data, 1); if (error == 0) { func = data & AXP2XX_GPIO_FUNC_MASK; if (func == AXP2XX_GPIO_FUNC_INPUT) *flags = GPIO_PIN_INPUT; else if (func == AXP2XX_GPIO_FUNC_DRVLO || func == AXP2XX_GPIO_FUNC_DRVHI) *flags = GPIO_PIN_OUTPUT; else *flags = 0; } AXP_UNLOCK(sc); return (error); } static int axp2xx_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) { struct axp2xx_softc *sc; uint8_t data; int error; sc = device_get_softc(dev); if (pin >= sc->npins) return (EINVAL); AXP_LOCK(sc); error = axp2xx_read(dev, sc->pins[pin].ctrl_reg, &data, 1); if (error == 0) { data &= ~AXP2XX_GPIO_FUNC_MASK; if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) != 0) { if ((flags & GPIO_PIN_OUTPUT) == 0) data |= AXP2XX_GPIO_FUNC_INPUT; } error = axp2xx_write(dev, sc->pins[pin].ctrl_reg, data); } AXP_UNLOCK(sc); return (error); } static int axp2xx_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) { struct axp2xx_softc *sc; uint8_t data, func; int error; sc = device_get_softc(dev); if (pin >= sc->npins) return (EINVAL); AXP_LOCK(sc); error = axp2xx_read(dev, sc->pins[pin].ctrl_reg, &data, 1); if (error == 0) { func = data & AXP2XX_GPIO_FUNC_MASK; switch (func) { case AXP2XX_GPIO_FUNC_DRVLO: *val = 0; break; case AXP2XX_GPIO_FUNC_DRVHI: *val = 1; break; case AXP2XX_GPIO_FUNC_INPUT: error = axp2xx_read(dev, sc->pins[pin].status_reg, &data, 1); if (error == 0) { *val = (data & sc->pins[pin].status_mask); *val >>= sc->pins[pin].status_shift; } break; default: error = EIO; break; } } AXP_UNLOCK(sc); return (error); } static int axp2xx_gpio_pin_set(device_t dev, uint32_t pin, unsigned int val) { struct axp2xx_softc *sc; uint8_t data, func; int error; sc = device_get_softc(dev); if (pin >= sc->npins) return (EINVAL); AXP_LOCK(sc); error = axp2xx_read(dev, sc->pins[pin].ctrl_reg, &data, 1); if (error == 0) { func = data & AXP2XX_GPIO_FUNC_MASK; switch (func) { case AXP2XX_GPIO_FUNC_DRVLO: case AXP2XX_GPIO_FUNC_DRVHI: /* GPIO2 can't be set to 1 */ if (pin == 2 && val == 1) { error = EINVAL; break; } data &= ~AXP2XX_GPIO_FUNC_MASK; data |= val; break; default: error = EIO; break; } } if (error == 0) error = axp2xx_write(dev, sc->pins[pin].ctrl_reg, data); AXP_UNLOCK(sc); return (error); } static int axp2xx_gpio_pin_toggle(device_t dev, uint32_t pin) { struct axp2xx_softc *sc; uint8_t data, func; int error; sc = device_get_softc(dev); if (pin >= sc->npins) return (EINVAL); AXP_LOCK(sc); error = axp2xx_read(dev, sc->pins[pin].ctrl_reg, &data, 1); if (error == 0) { func = data & AXP2XX_GPIO_FUNC_MASK; switch (func) { case AXP2XX_GPIO_FUNC_DRVLO: /* Pin 2 can't be set to 1*/ if (pin == 2) { error = EINVAL; break; } data &= ~AXP2XX_GPIO_FUNC_MASK; data |= AXP2XX_GPIO_FUNC_DRVHI; break; case AXP2XX_GPIO_FUNC_DRVHI: data &= ~AXP2XX_GPIO_FUNC_MASK; data |= AXP2XX_GPIO_FUNC_DRVLO; break; default: error = EIO; break; } } if (error == 0) error = axp2xx_write(dev, sc->pins[pin].ctrl_reg, data); AXP_UNLOCK(sc); return (error); } static int axp2xx_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent, int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags) { struct axp2xx_softc *sc; sc = device_get_softc(bus); if (gpios[0] >= sc->npins) return (EINVAL); *pin = gpios[0]; *flags = gpios[1]; return (0); } static phandle_t axp2xx_get_node(device_t dev, device_t bus) { return (ofw_bus_get_node(dev)); } static struct axp2xx_reg_sc * axp2xx_reg_attach(device_t dev, phandle_t node, struct axp2xx_regdef *def) { struct axp2xx_reg_sc *reg_sc; struct regnode_init_def initdef; struct regnode *regnode; memset(&initdef, 0, sizeof(initdef)); if (regulator_parse_ofw_stdparam(dev, node, &initdef) != 0) { device_printf(dev, "cannot create regulator\n"); return (NULL); } if (initdef.std_param.min_uvolt == 0) initdef.std_param.min_uvolt = def->voltage_min * 1000; if (initdef.std_param.max_uvolt == 0) initdef.std_param.max_uvolt = def->voltage_max * 1000; initdef.id = def->id; initdef.ofw_node = node; regnode = regnode_create(dev, &axp2xx_regnode_class, &initdef); if (regnode == NULL) { device_printf(dev, "cannot create regulator\n"); return (NULL); } reg_sc = regnode_get_softc(regnode); reg_sc->regnode = regnode; reg_sc->base_dev = dev; reg_sc->def = def; reg_sc->xref = OF_xref_from_node(node); reg_sc->param = regnode_get_stdparam(regnode); regnode_register(regnode); return (reg_sc); } static int axp2xx_regdev_map(device_t dev, phandle_t xref, int ncells, pcell_t *cells, intptr_t *num) { struct axp2xx_softc *sc; int i; sc = device_get_softc(dev); for (i = 0; i < sc->nregs; i++) { if (sc->regs[i] == NULL) continue; if (sc->regs[i]->xref == xref) { *num = sc->regs[i]->def->id; return (0); } } return (ENXIO); } static void axp2xx_start(void *pdev) { device_t dev; struct axp2xx_softc *sc; const char *pwr_name[] = {"Battery", "AC", "USB", "AC and USB"}; int i; uint8_t reg, data; uint8_t pwr_src; dev = pdev; sc = device_get_softc(dev); sc->dev = dev; if (bootverbose) { /* * Read the Power State register. * Shift the AC presence into bit 0. * Shift the Battery presence into bit 1. */ axp2xx_read(dev, AXP2XX_PSR, &data, 1); pwr_src = ((data & AXP2XX_PSR_ACIN) >> AXP2XX_PSR_ACIN_SHIFT) | ((data & AXP2XX_PSR_VBUS) >> (AXP2XX_PSR_VBUS_SHIFT - 1)); device_printf(dev, "Powered by %s\n", pwr_name[pwr_src]); } /* Only enable interrupts that we are interested in */ axp2xx_write(dev, AXP2XX_IRQ1_ENABLE, AXP2XX_IRQ1_AC_OVERVOLT | AXP2XX_IRQ1_AC_DISCONN | AXP2XX_IRQ1_AC_CONN | AXP2XX_IRQ1_VBUS_OVERVOLT | AXP2XX_IRQ1_VBUS_DISCONN | AXP2XX_IRQ1_VBUS_CONN); axp2xx_write(dev, AXP2XX_IRQ2_ENABLE, AXP2XX_IRQ2_BATT_CONN | AXP2XX_IRQ2_BATT_DISCONN | AXP2XX_IRQ2_BATT_CHARGE_ACCT_ON | AXP2XX_IRQ2_BATT_CHARGE_ACCT_OFF | AXP2XX_IRQ2_BATT_CHARGING | AXP2XX_IRQ2_BATT_CHARGED | AXP2XX_IRQ2_BATT_TEMP_OVER | AXP2XX_IRQ2_BATT_TEMP_LOW); axp2xx_write(dev, AXP2XX_IRQ3_ENABLE, AXP2XX_IRQ3_PEK_SHORT | AXP2XX_IRQ3_PEK_LONG); axp2xx_write(dev, AXP2XX_IRQ4_ENABLE, AXP2XX_IRQ4_APS_LOW_2); axp2xx_write(dev, AXP2XX_IRQ5_ENABLE, 0x0); EVENTHANDLER_REGISTER(shutdown_final, axp2xx_shutdown, dev, SHUTDOWN_PRI_LAST); /* Enable ADC sensors */ for (i = 0; i < sc->nsensors; i++) { if (axp2xx_read(dev, sc->sensors[i].enable_reg, ®, 1) == -1) { device_printf(dev, "Cannot enable sensor '%s'\n", sc->sensors[i].name); continue; } reg |= sc->sensors[i].enable_mask; if (axp2xx_write(dev, sc->sensors[i].enable_reg, reg) == -1) { device_printf(dev, "Cannot enable sensor '%s'\n", sc->sensors[i].name); continue; } SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, sc->sensors[i].name, CTLTYPE_INT | CTLFLAG_RD, dev, sc->sensors[i].id, axp2xx_sysctl, sc->sensors[i].format, sc->sensors[i].desc); } if ((bus_setup_intr(dev, sc->res[0], INTR_TYPE_MISC | INTR_MPSAFE, NULL, axp2xx_intr, sc, &sc->intrcookie))) device_printf(dev, "unable to register interrupt handler\n"); config_intrhook_disestablish(&sc->intr_hook); } static int axp2xx_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) { case AXP209: device_set_desc(dev, "X-Powers AXP209 Power Management Unit"); break; case AXP221: device_set_desc(dev, "X-Powers AXP221 Power Management Unit"); break; default: return (ENXIO); } return (BUS_PROBE_DEFAULT); } static int axp2xx_attach(device_t dev) { struct axp2xx_softc *sc; struct axp2xx_reg_sc *reg; struct axp2xx_regdef *regdefs; phandle_t rnode, child; int i; sc = device_get_softc(dev); mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); if (bus_alloc_resources(dev, axp_res_spec, sc->res) != 0) { device_printf(dev, "can't allocate device resources\n"); return (ENXIO); } sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; switch (sc->type) { case AXP209: sc->pins = axp209_pins; sc->npins = nitems(axp209_pins); sc->gpiodev = gpiobus_attach_bus(dev); sc->sensors = axp209_sensors; sc->nsensors = nitems(axp209_sensors); regdefs = axp209_regdefs; sc->nregs = nitems(axp209_regdefs); break; case AXP221: sc->pins = axp221_pins; sc->npins = nitems(axp221_pins); sc->gpiodev = gpiobus_attach_bus(dev); sc->sensors = axp221_sensors; sc->nsensors = nitems(axp221_sensors); regdefs = axp221_regdefs; sc->nregs = nitems(axp221_regdefs); break; } sc->regs = malloc(sizeof(struct axp2xx_reg_sc *) * sc->nregs, M_AXP2XX_REG, M_WAITOK | M_ZERO); sc->intr_hook.ich_func = axp2xx_start; sc->intr_hook.ich_arg = dev; if (config_intrhook_establish(&sc->intr_hook) != 0) return (ENOMEM); /* Attach known regulators that exist in the DT */ rnode = ofw_bus_find_child(ofw_bus_get_node(dev), "regulators"); if (rnode > 0) { for (i = 0; i < sc->nregs; i++) { child = ofw_bus_find_child(rnode, regdefs[i].name); if (child == 0) continue; reg = axp2xx_reg_attach(dev, child, ®defs[i]); if (reg == NULL) { device_printf(dev, "cannot attach regulator %s\n", regdefs[i].name); continue; } sc->regs[i] = reg; if (bootverbose) device_printf(dev, "Regulator %s attached\n", regdefs[i].name); } } return (0); } static device_method_t axp2xx_methods[] = { DEVMETHOD(device_probe, axp2xx_probe), DEVMETHOD(device_attach, axp2xx_attach), /* GPIO interface */ DEVMETHOD(gpio_get_bus, axp2xx_gpio_get_bus), DEVMETHOD(gpio_pin_max, axp2xx_gpio_pin_max), DEVMETHOD(gpio_pin_getname, axp2xx_gpio_pin_getname), DEVMETHOD(gpio_pin_getcaps, axp2xx_gpio_pin_getcaps), DEVMETHOD(gpio_pin_getflags, axp2xx_gpio_pin_getflags), DEVMETHOD(gpio_pin_setflags, axp2xx_gpio_pin_setflags), DEVMETHOD(gpio_pin_get, axp2xx_gpio_pin_get), DEVMETHOD(gpio_pin_set, axp2xx_gpio_pin_set), DEVMETHOD(gpio_pin_toggle, axp2xx_gpio_pin_toggle), DEVMETHOD(gpio_map_gpios, axp2xx_gpio_map_gpios), /* Regdev interface */ DEVMETHOD(regdev_map, axp2xx_regdev_map), /* OFW bus interface */ DEVMETHOD(ofw_bus_get_node, axp2xx_get_node), DEVMETHOD_END }; static driver_t axp2xx_driver = { "axp2xx_pmu", axp2xx_methods, sizeof(struct axp2xx_softc), }; static devclass_t axp2xx_devclass; extern devclass_t ofwgpiobus_devclass, gpioc_devclass; extern driver_t ofw_gpiobus_driver, gpioc_driver; EARLY_DRIVER_MODULE(axp2xx, iicbus, axp2xx_driver, axp2xx_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE); EARLY_DRIVER_MODULE(ofw_gpiobus, axp2xx_pmu, ofw_gpiobus_driver, ofwgpiobus_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE); DRIVER_MODULE(gpioc, axp2xx_pmu, gpioc_driver, gpioc_devclass, 0, 0); MODULE_VERSION(axp2xx, 1); MODULE_DEPEND(axp2xx, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); Index: head/sys/arm/allwinner/axp209reg.h =================================================================== --- head/sys/arm/allwinner/axp209reg.h (revision 355356) +++ head/sys/arm/allwinner/axp209reg.h (revision 355357) @@ -1,248 +1,247 @@ /*- * Copyright (c) 2016 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _AXP209REG_H_ #define _AXP209REG_H_ /* Power State Register */ #define AXP2XX_PSR 0x00 #define AXP2XX_PSR_ACIN 0x80 #define AXP2XX_PSR_ACIN_SHIFT 7 #define AXP2XX_PSR_VBUS 0x20 #define AXP2XX_PSR_VBUS_SHIFT 5 /* Shutdown and battery control */ #define AXP2XX_SHUTBAT 0x32 #define AXP2XX_SHUTBAT_SHUTDOWN 0x80 /* Voltage/Current Monitor */ #define AXP209_ACIN_VOLTAGE 0x56 #define AXP209_ACIN_CURRENT 0x58 #define AXP209_VBUS_VOLTAGE 0x5A #define AXP209_VBUS_CURRENT 0x5C #define AXP2XX_BAT_VOLTAGE 0x78 #define AXP2XX_BAT_CHARGE_CURRENT 0x7A #define AXP2XX_BAT_DISCHARGE_CURRENT 0x7C #define AXP209_VOLT_STEP 1700 #define AXP2XX_BATVOLT_STEP 1100 #define AXP209_ACCURRENT_STEP 625 #define AXP209_VBUSCURRENT_STEP 375 #define AXP2XX_BATCURRENT_STEP 500 /* Temperature monitor */ #define AXP209_TEMPMON 0x5e #define AXP209_TEMPMON_MIN 1447 /* -144.7C */ #define AXP221_TEMPMON_MIN 2437 /* -243.7C */ #define AXP221_TEMPMON 0x56 /* Sensors conversion macros */ #define AXP209_SENSOR_H(a) ((a) << 4) #define AXP209_SENSOR_L(a) ((a) & 0xf) #define AXP209_SENSOR_BAT_H(a) ((a) << 5) #define AXP209_SENSOR_BAT_L(a) ((a) & 0x1f) #define AXP209_0C_TO_K 2732 /* ADC Sensors */ #define AXP2XX_ADC_ENABLE1 0x82 #define AXP209_ADC_ENABLE2 0x83 #define AXP2XX_ADC1_BATVOLT (1 << 7) #define AXP2XX_ADC1_BATCURRENT (1 << 6) #define AXP209_ADC1_ACVOLT (1 << 5) #define AXP221_ADC1_TEMP (1 << 5) #define AXP209_ADC1_ACCURRENT (1 << 4) #define AXP209_ADC1_VBUSVOLT (1 << 3) #define AXP209_ADC1_VBUSCURRENT (1 << 2) #define AXP221_ADC1_TS_PIN (1 << 0) #define AXP209_ADC2_TEMP (1 << 7) /* Interrupt related registers */ #define AXP2XX_IRQ1_ENABLE 0x40 #define AXP2XX_IRQ1_STATUS 0x48 #define AXP2XX_IRQ1_AC_OVERVOLT (1 << 7) #define AXP2XX_IRQ1_AC_CONN (1 << 6) #define AXP2XX_IRQ1_AC_DISCONN (1 << 5) #define AXP2XX_IRQ1_VBUS_OVERVOLT (1 << 4) #define AXP2XX_IRQ1_VBUS_CONN (1 << 3) #define AXP2XX_IRQ1_VBUS_DISCONN (1 << 2) #define AXP2XX_IRQ1_VBUS_LOW (1 << 1) #define AXP2XX_IRQ2_ENABLE 0x41 #define AXP2XX_IRQ2_STATUS 0x49 #define AXP2XX_IRQ2_BATT_CONN (1 << 7) #define AXP2XX_IRQ2_BATT_DISCONN (1 << 6) #define AXP2XX_IRQ2_BATT_CHARGE_ACCT_ON (1 << 5) #define AXP2XX_IRQ2_BATT_CHARGE_ACCT_OFF (1 << 4) #define AXP2XX_IRQ2_BATT_CHARGING (1 << 3) #define AXP2XX_IRQ2_BATT_CHARGED (1 << 2) #define AXP2XX_IRQ2_BATT_TEMP_OVER (1 << 1) #define AXP2XX_IRQ2_BATT_TEMP_LOW (1 << 0) #define AXP2XX_IRQ3_ENABLE 0x42 #define AXP2XX_IRQ3_STATUS 0x4A #define AXP2XX_IRQ3_TEMP_OVER (1 << 7) #define AXP2XX_IRQ3_CHARGE_CURRENT_LOW (1 << 6) #define AXP2XX_IRQ3_DCDC2_LOW (1 << 4) #define AXP2XX_IRQ3_DCDC3_LOW (1 << 3) #define AXP2XX_IRQ3_LDO3_LOW (1 << 2) #define AXP2XX_IRQ3_PEK_SHORT (1 << 1) #define AXP2XX_IRQ3_PEK_LONG (1 << 0) #define AXP2XX_IRQ4_ENABLE 0x43 #define AXP2XX_IRQ4_STATUS 0x4B #define AXP2XX_IRQ4_NOE_START (1 << 7) #define AXP2XX_IRQ4_NOE_SHUT (1 << 6) #define AXP2XX_IRQ4_VBUS_VALID (1 << 5) #define AXP2XX_IRQ4_VBUS_INVALID (1 << 4) #define AXP2XX_IRQ4_VBUS_SESSION (1 << 3) #define AXP2XX_IRQ4_VBUS_SESSION_END (1 << 2) #define AXP2XX_IRQ4_APS_LOW_1 (1 << 1) #define AXP2XX_IRQ4_APS_LOW_2 (1 << 0) #define AXP2XX_IRQ5_ENABLE 0x44 #define AXP2XX_IRQ5_STATUS 0x4C #define AXP2XX_IRQ5_TIMER_EXPIRE (1 << 7) #define AXP2XX_IRQ5_PEK_RISE_EDGE (1 << 6) #define AXP2XX_IRQ5_PEK_FALL_EDGE (1 << 5) #define AXP2XX_IRQ5_GPIO3 (1 << 3) #define AXP2XX_IRQ5_GPIO2 (1 << 2) #define AXP2XX_IRQ5_GPIO1 (1 << 1) #define AXP2XX_IRQ5_GPIO0 (1 << 0) #define AXP2XX_IRQ_ACK 0xff /* GPIOs registers */ #define AXP2XX_GPIO_FUNC_MASK 0x7 #define AXP2XX_GPIO_FUNC_DRVLO 0x0 #define AXP2XX_GPIO_FUNC_DRVHI 0x1 #define AXP2XX_GPIO_FUNC_INPUT 0x2 #define AXP2XX_GPIO0_CTRL 0x90 #define AXP2XX_GPIO1_CTRL 0x92 #define AXP209_GPIO2_CTRL 0x93 #define AXP2XX_GPIO_STATUS 0x94 /* Regulators registers */ #define AXP209_POWERCTL 0x12 #define AXP209_POWERCTL_LDO3 (1 << 6) #define AXP209_POWERCTL_DCDC2 (1 << 4) #define AXP209_POWERCTL_LDO4 (1 << 3) #define AXP209_POWERCTL_LDO2 (1 << 2) #define AXP209_POWERCTL_DCDC3 (1 << 1) #define AXP221_POWERCTL_1 0x10 #define AXP221_POWERCTL1_ALDO2 (1 << 7) #define AXP221_POWERCTL1_ALDO1 (1 << 6) #define AXP221_POWERCTL1_DCDC5 (1 << 5) #define AXP221_POWERCTL1_DCDC4 (1 << 4) #define AXP221_POWERCTL1_DCDC3 (1 << 3) #define AXP221_POWERCTL1_DCDC2 (1 << 2) #define AXP221_POWERCTL1_DCDC1 (1 << 1) #define AXP221_POWERCTL1_DC5LDO (1 << 0) #define AXP221_POWERCTL_2 0x12 #define AXP221_POWERCTL2_DC1SW (1 << 7) #define AXP221_POWERCTL2_DLDO4 (1 << 6) #define AXP221_POWERCTL2_DLDO3 (1 << 5) #define AXP221_POWERCTL2_DLDO2 (1 << 4) #define AXP221_POWERCTL2_DLDO1 (1 << 3) #define AXP221_POWERCTL2_ELDO3 (1 << 2) #define AXP221_POWERCTL2_ELDO2 (1 << 1) #define AXP221_POWERCTL2_ELDO1 (1 << 0) #define AXP221_POWERCTL_3 0x14 #define AXP221_POWERCTL3_ALDO3 (1 << 7) #define AXP209_REG_DCDC2_VOLTAGE 0x23 #define AXP209_REG_DCDC3_VOLTAGE 0x27 #define AXP209_REG_LDO24_VOLTAGE 0x28 #define AXP209_REG_LDO3_VOLTAGE 0x29 #define AXP221_REG_DLDO1_VOLTAGE 0x15 #define AXP221_REG_DLDO2_VOLTAGE 0x16 #define AXP221_REG_DLDO3_VOLTAGE 0x17 #define AXP221_REG_DLDO4_VOLTAGE 0x18 #define AXP221_REG_ELDO1_VOLTAGE 0x19 #define AXP221_REG_ELDO2_VOLTAGE 0x1A #define AXP221_REG_ELDO3_VOLTAGE 0x1B #define AXP221_REG_DC5LDO_VOLTAGE 0x1C #define AXP221_REG_DCDC1_VOLTAGE 0x21 #define AXP221_REG_DCDC2_VOLTAGE 0x22 #define AXP221_REG_DCDC3_VOLTAGE 0x23 #define AXP221_REG_DCDC4_VOLTAGE 0x24 #define AXP221_REG_DCDC5_VOLTAGE 0x25 #define AXP221_REG_DCDC23_VRC 0x27 #define AXP221_REG_ALDO1_VOLTAGE 0x28 #define AXP221_REG_ALDO2_VOLTAGE 0x29 #define AXP221_REG_ALDO3_VOLTAGE 0x2A enum axp2xx_sensor { AXP209_ACVOLT, AXP209_ACCURRENT, AXP209_VBUSVOLT, AXP209_VBUSCURRENT, AXP2XX_TEMP, AXP2XX_BATVOLT, AXP2XX_BATCHARGECURRENT, AXP2XX_BATDISCHARGECURRENT, }; enum axp2xx_regulators { AXP209_REG_ID_DCDC2, AXP209_REG_ID_DCDC3, AXP209_REG_ID_LDO1, AXP209_REG_ID_LDO2, AXP209_REG_ID_LDO3, /* LDO4 is weird, need to find a correct way to handle it */ /* AXP209_REG_ID_LDO4, */ AXP209_REG_ID_LDO5, AXP221_REG_ID_DLDO1, AXP221_REG_ID_DLDO2, AXP221_REG_ID_DLDO3, AXP221_REG_ID_DLDO4, AXP221_REG_ID_ELDO1, AXP221_REG_ID_ELDO2, AXP221_REG_ID_ELDO3, AXP221_REG_ID_DC5LDO, AXP221_REG_ID_DCDC1, AXP221_REG_ID_DCDC2, AXP221_REG_ID_DCDC3, AXP221_REG_ID_DCDC4, AXP221_REG_ID_DCDC5, AXP221_REG_ID_ALDO1, AXP221_REG_ID_ALDO2, AXP221_REG_ID_ALDO3, AXP221_REG_ID_DC1SW, }; #endif /* _AXP209REG_H_ */ Index: head/sys/arm/allwinner/axp81x.c =================================================================== --- head/sys/arm/allwinner/axp81x.c (revision 355356) +++ head/sys/arm/allwinner/axp81x.c (revision 355357) @@ -1,1616 +1,1615 @@ /*- * Copyright (c) 2018 Emmanuel Vadot * Copyright (c) 2016 Jared McNeill - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * X-Powers AXP803/813/818 PMU for Allwinner SoCs */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gpio_if.h" #include "iicbus_if.h" #include "regdev_if.h" MALLOC_DEFINE(M_AXP8XX_REG, "AXP8xx regulator", "AXP8xx power regulator"); #define AXP_POWERSRC 0x00 #define AXP_POWERSRC_ACIN (1 << 7) #define AXP_POWERSRC_VBUS (1 << 5) #define AXP_POWERSRC_VBAT (1 << 3) #define AXP_POWERSRC_CHARING (1 << 2) /* Charging Direction */ #define AXP_POWERSRC_SHORTED (1 << 1) #define AXP_POWERSRC_STARTUP (1 << 0) #define AXP_POWERMODE 0x01 #define AXP_POWERMODE_BAT_CHARGING (1 << 6) #define AXP_POWERMODE_BAT_PRESENT (1 << 5) #define AXP_POWERMODE_BAT_VALID (1 << 4) #define AXP_ICTYPE 0x03 #define AXP_POWERCTL1 0x10 #define AXP_POWERCTL1_DCDC7 (1 << 6) /* AXP813/818 only */ #define AXP_POWERCTL1_DCDC6 (1 << 5) #define AXP_POWERCTL1_DCDC5 (1 << 4) #define AXP_POWERCTL1_DCDC4 (1 << 3) #define AXP_POWERCTL1_DCDC3 (1 << 2) #define AXP_POWERCTL1_DCDC2 (1 << 1) #define AXP_POWERCTL1_DCDC1 (1 << 0) #define AXP_POWERCTL2 0x12 #define AXP_POWERCTL2_DC1SW (1 << 7) /* AXP803 only */ #define AXP_POWERCTL2_DLDO4 (1 << 6) #define AXP_POWERCTL2_DLDO3 (1 << 5) #define AXP_POWERCTL2_DLDO2 (1 << 4) #define AXP_POWERCTL2_DLDO1 (1 << 3) #define AXP_POWERCTL2_ELDO3 (1 << 2) #define AXP_POWERCTL2_ELDO2 (1 << 1) #define AXP_POWERCTL2_ELDO1 (1 << 0) #define AXP_POWERCTL3 0x13 #define AXP_POWERCTL3_ALDO3 (1 << 7) #define AXP_POWERCTL3_ALDO2 (1 << 6) #define AXP_POWERCTL3_ALDO1 (1 << 5) #define AXP_POWERCTL3_FLDO3 (1 << 4) /* AXP813/818 only */ #define AXP_POWERCTL3_FLDO2 (1 << 3) #define AXP_POWERCTL3_FLDO1 (1 << 2) #define AXP_VOLTCTL_DLDO1 0x15 #define AXP_VOLTCTL_DLDO2 0x16 #define AXP_VOLTCTL_DLDO3 0x17 #define AXP_VOLTCTL_DLDO4 0x18 #define AXP_VOLTCTL_ELDO1 0x19 #define AXP_VOLTCTL_ELDO2 0x1A #define AXP_VOLTCTL_ELDO3 0x1B #define AXP_VOLTCTL_FLDO1 0x1C #define AXP_VOLTCTL_FLDO2 0x1D #define AXP_VOLTCTL_DCDC1 0x20 #define AXP_VOLTCTL_DCDC2 0x21 #define AXP_VOLTCTL_DCDC3 0x22 #define AXP_VOLTCTL_DCDC4 0x23 #define AXP_VOLTCTL_DCDC5 0x24 #define AXP_VOLTCTL_DCDC6 0x25 #define AXP_VOLTCTL_DCDC7 0x26 #define AXP_VOLTCTL_ALDO1 0x28 #define AXP_VOLTCTL_ALDO2 0x29 #define AXP_VOLTCTL_ALDO3 0x2A #define AXP_VOLTCTL_STATUS (1 << 7) #define AXP_VOLTCTL_MASK 0x7f #define AXP_POWERBAT 0x32 #define AXP_POWERBAT_SHUTDOWN (1 << 7) #define AXP_CHARGERCTL1 0x33 #define AXP_CHARGERCTL1_MIN 0 #define AXP_CHARGERCTL1_MAX 13 #define AXP_CHARGERCTL1_CMASK 0xf #define AXP_IRQEN1 0x40 #define AXP_IRQEN1_ACIN_HI (1 << 6) #define AXP_IRQEN1_ACIN_LO (1 << 5) #define AXP_IRQEN1_VBUS_HI (1 << 3) #define AXP_IRQEN1_VBUS_LO (1 << 2) #define AXP_IRQEN2 0x41 #define AXP_IRQEN2_BAT_IN (1 << 7) #define AXP_IRQEN2_BAT_NO (1 << 6) #define AXP_IRQEN2_BATCHGC (1 << 3) #define AXP_IRQEN2_BATCHGD (1 << 2) #define AXP_IRQEN3 0x42 #define AXP_IRQEN4 0x43 #define AXP_IRQEN4_BATLVL_LO1 (1 << 1) #define AXP_IRQEN4_BATLVL_LO0 (1 << 0) #define AXP_IRQEN5 0x44 #define AXP_IRQEN5_POKSIRQ (1 << 4) #define AXP_IRQEN5_POKLIRQ (1 << 3) #define AXP_IRQEN6 0x45 #define AXP_IRQSTAT1 0x48 #define AXP_IRQSTAT1_ACIN_HI (1 << 6) #define AXP_IRQSTAT1_ACIN_LO (1 << 5) #define AXP_IRQSTAT1_VBUS_HI (1 << 3) #define AXP_IRQSTAT1_VBUS_LO (1 << 2) #define AXP_IRQSTAT2 0x49 #define AXP_IRQSTAT2_BAT_IN (1 << 7) #define AXP_IRQSTAT2_BAT_NO (1 << 6) #define AXP_IRQSTAT2_BATCHGC (1 << 3) #define AXP_IRQSTAT2_BATCHGD (1 << 2) #define AXP_IRQSTAT3 0x4a #define AXP_IRQSTAT4 0x4b #define AXP_IRQSTAT4_BATLVL_LO1 (1 << 1) #define AXP_IRQSTAT4_BATLVL_LO0 (1 << 0) #define AXP_IRQSTAT5 0x4c #define AXP_IRQSTAT5_POKSIRQ (1 << 4) #define AXP_IRQEN5_POKLIRQ (1 << 3) #define AXP_IRQSTAT6 0x4d #define AXP_BATSENSE_HI 0x78 #define AXP_BATSENSE_LO 0x79 #define AXP_BATCHG_HI 0x7a #define AXP_BATCHG_LO 0x7b #define AXP_BATDISCHG_HI 0x7c #define AXP_BATDISCHG_LO 0x7d #define AXP_GPIO0_CTRL 0x90 #define AXP_GPIO0LDO_CTRL 0x91 #define AXP_GPIO1_CTRL 0x92 #define AXP_GPIO1LDO_CTRL 0x93 #define AXP_GPIO_FUNC (0x7 << 0) #define AXP_GPIO_FUNC_SHIFT 0 #define AXP_GPIO_FUNC_DRVLO 0 #define AXP_GPIO_FUNC_DRVHI 1 #define AXP_GPIO_FUNC_INPUT 2 #define AXP_GPIO_FUNC_LDO_ON 3 #define AXP_GPIO_FUNC_LDO_OFF 4 #define AXP_GPIO_SIGBIT 0x94 #define AXP_GPIO_PD 0x97 #define AXP_FUEL_GAUGECTL 0xb8 #define AXP_FUEL_GAUGECTL_EN (1 << 7) #define AXP_BAT_CAP 0xb9 #define AXP_BAT_CAP_VALID (1 << 7) #define AXP_BAT_CAP_PERCENT 0x7f #define AXP_BAT_MAX_CAP_HI 0xe0 #define AXP_BAT_MAX_CAP_VALID (1 << 7) #define AXP_BAT_MAX_CAP_LO 0xe1 #define AXP_BAT_COULOMB_HI 0xe2 #define AXP_BAT_COULOMB_VALID (1 << 7) #define AXP_BAT_COULOMB_LO 0xe3 #define AXP_BAT_CAP_WARN 0xe6 #define AXP_BAT_CAP_WARN_LV1 0xf0 /* Bits 4, 5, 6, 7 */ #define AXP_BAP_CAP_WARN_LV1BASE 5 /* 5-20%, 1% per step */ #define AXP_BAT_CAP_WARN_LV2 0xf /* Bits 0, 1, 2, 3 */ /* Sensor conversion macros */ #define AXP_SENSOR_BAT_H(hi) ((hi) << 4) #define AXP_SENSOR_BAT_L(lo) ((lo) & 0xf) #define AXP_SENSOR_COULOMB(hi, lo) (((hi & ~(1 << 7)) << 8) | (lo)) static const struct { const char *name; uint8_t ctrl_reg; } axp8xx_pins[] = { { "GPIO0", AXP_GPIO0_CTRL }, { "GPIO1", AXP_GPIO1_CTRL }, }; enum AXP8XX_TYPE { AXP803 = 1, AXP813, }; static struct ofw_compat_data compat_data[] = { { "x-powers,axp803", AXP803 }, { "x-powers,axp813", AXP813 }, { "x-powers,axp818", AXP813 }, { NULL, 0 } }; static struct resource_spec axp8xx_spec[] = { { SYS_RES_IRQ, 0, RF_ACTIVE }, { -1, 0 } }; struct axp8xx_regdef { intptr_t id; char *name; char *supply_name; uint8_t enable_reg; uint8_t enable_mask; uint8_t enable_value; uint8_t disable_value; uint8_t voltage_reg; int voltage_min; int voltage_max; int voltage_step1; int voltage_nstep1; int voltage_step2; int voltage_nstep2; }; enum axp8xx_reg_id { AXP8XX_REG_ID_DCDC1 = 100, AXP8XX_REG_ID_DCDC2, AXP8XX_REG_ID_DCDC3, AXP8XX_REG_ID_DCDC4, AXP8XX_REG_ID_DCDC5, AXP8XX_REG_ID_DCDC6, AXP813_REG_ID_DCDC7, AXP803_REG_ID_DC1SW, AXP8XX_REG_ID_DLDO1, AXP8XX_REG_ID_DLDO2, AXP8XX_REG_ID_DLDO3, AXP8XX_REG_ID_DLDO4, AXP8XX_REG_ID_ELDO1, AXP8XX_REG_ID_ELDO2, AXP8XX_REG_ID_ELDO3, AXP8XX_REG_ID_ALDO1, AXP8XX_REG_ID_ALDO2, AXP8XX_REG_ID_ALDO3, AXP8XX_REG_ID_FLDO1, AXP8XX_REG_ID_FLDO2, AXP813_REG_ID_FLDO3, AXP8XX_REG_ID_GPIO0_LDO, AXP8XX_REG_ID_GPIO1_LDO, }; static struct axp8xx_regdef axp803_regdefs[] = { { .id = AXP803_REG_ID_DC1SW, .name = "dc1sw", .enable_reg = AXP_POWERCTL2, .enable_mask = (uint8_t) AXP_POWERCTL2_DC1SW, .enable_value = AXP_POWERCTL2_DC1SW, }, }; static struct axp8xx_regdef axp813_regdefs[] = { { .id = AXP813_REG_ID_DCDC7, .name = "dcdc7", .enable_reg = AXP_POWERCTL1, .enable_mask = (uint8_t) AXP_POWERCTL1_DCDC7, .enable_value = AXP_POWERCTL1_DCDC7, .voltage_reg = AXP_VOLTCTL_DCDC7, .voltage_min = 600, .voltage_max = 1520, .voltage_step1 = 10, .voltage_nstep1 = 50, .voltage_step2 = 20, .voltage_nstep2 = 21, }, }; static struct axp8xx_regdef axp8xx_common_regdefs[] = { { .id = AXP8XX_REG_ID_DCDC1, .name = "dcdc1", .enable_reg = AXP_POWERCTL1, .enable_mask = (uint8_t) AXP_POWERCTL1_DCDC1, .enable_value = AXP_POWERCTL1_DCDC1, .voltage_reg = AXP_VOLTCTL_DCDC1, .voltage_min = 1600, .voltage_max = 3400, .voltage_step1 = 100, .voltage_nstep1 = 18, }, { .id = AXP8XX_REG_ID_DCDC2, .name = "dcdc2", .enable_reg = AXP_POWERCTL1, .enable_mask = (uint8_t) AXP_POWERCTL1_DCDC2, .enable_value = AXP_POWERCTL1_DCDC2, .voltage_reg = AXP_VOLTCTL_DCDC2, .voltage_min = 500, .voltage_max = 1300, .voltage_step1 = 10, .voltage_nstep1 = 70, .voltage_step2 = 20, .voltage_nstep2 = 5, }, { .id = AXP8XX_REG_ID_DCDC3, .name = "dcdc3", .enable_reg = AXP_POWERCTL1, .enable_mask = (uint8_t) AXP_POWERCTL1_DCDC3, .enable_value = AXP_POWERCTL1_DCDC3, .voltage_reg = AXP_VOLTCTL_DCDC3, .voltage_min = 500, .voltage_max = 1300, .voltage_step1 = 10, .voltage_nstep1 = 70, .voltage_step2 = 20, .voltage_nstep2 = 5, }, { .id = AXP8XX_REG_ID_DCDC4, .name = "dcdc4", .enable_reg = AXP_POWERCTL1, .enable_mask = (uint8_t) AXP_POWERCTL1_DCDC4, .enable_value = AXP_POWERCTL1_DCDC4, .voltage_reg = AXP_VOLTCTL_DCDC4, .voltage_min = 500, .voltage_max = 1300, .voltage_step1 = 10, .voltage_nstep1 = 70, .voltage_step2 = 20, .voltage_nstep2 = 5, }, { .id = AXP8XX_REG_ID_DCDC5, .name = "dcdc5", .enable_reg = AXP_POWERCTL1, .enable_mask = (uint8_t) AXP_POWERCTL1_DCDC5, .enable_value = AXP_POWERCTL1_DCDC5, .voltage_reg = AXP_VOLTCTL_DCDC5, .voltage_min = 800, .voltage_max = 1840, .voltage_step1 = 10, .voltage_nstep1 = 42, .voltage_step2 = 20, .voltage_nstep2 = 36, }, { .id = AXP8XX_REG_ID_DCDC6, .name = "dcdc6", .enable_reg = AXP_POWERCTL1, .enable_mask = (uint8_t) AXP_POWERCTL1_DCDC6, .enable_value = AXP_POWERCTL1_DCDC6, .voltage_reg = AXP_VOLTCTL_DCDC6, .voltage_min = 600, .voltage_max = 1520, .voltage_step1 = 10, .voltage_nstep1 = 50, .voltage_step2 = 20, .voltage_nstep2 = 21, }, { .id = AXP8XX_REG_ID_DLDO1, .name = "dldo1", .enable_reg = AXP_POWERCTL2, .enable_mask = (uint8_t) AXP_POWERCTL2_DLDO1, .enable_value = AXP_POWERCTL2_DLDO1, .voltage_reg = AXP_VOLTCTL_DLDO1, .voltage_min = 700, .voltage_max = 3300, .voltage_step1 = 100, .voltage_nstep1 = 26, }, { .id = AXP8XX_REG_ID_DLDO2, .name = "dldo2", .enable_reg = AXP_POWERCTL2, .enable_mask = (uint8_t) AXP_POWERCTL2_DLDO2, .enable_value = AXP_POWERCTL2_DLDO2, .voltage_reg = AXP_VOLTCTL_DLDO2, .voltage_min = 700, .voltage_max = 4200, .voltage_step1 = 100, .voltage_nstep1 = 27, .voltage_step2 = 200, .voltage_nstep2 = 4, }, { .id = AXP8XX_REG_ID_DLDO3, .name = "dldo3", .enable_reg = AXP_POWERCTL2, .enable_mask = (uint8_t) AXP_POWERCTL2_DLDO3, .enable_value = AXP_POWERCTL2_DLDO3, .voltage_reg = AXP_VOLTCTL_DLDO3, .voltage_min = 700, .voltage_max = 3300, .voltage_step1 = 100, .voltage_nstep1 = 26, }, { .id = AXP8XX_REG_ID_DLDO4, .name = "dldo4", .enable_reg = AXP_POWERCTL2, .enable_mask = (uint8_t) AXP_POWERCTL2_DLDO4, .enable_value = AXP_POWERCTL2_DLDO4, .voltage_reg = AXP_VOLTCTL_DLDO4, .voltage_min = 700, .voltage_max = 3300, .voltage_step1 = 100, .voltage_nstep1 = 26, }, { .id = AXP8XX_REG_ID_ALDO1, .name = "aldo1", .enable_reg = AXP_POWERCTL3, .enable_mask = (uint8_t) AXP_POWERCTL3_ALDO1, .enable_value = AXP_POWERCTL3_ALDO1, .voltage_min = 700, .voltage_max = 3300, .voltage_step1 = 100, .voltage_nstep1 = 26, }, { .id = AXP8XX_REG_ID_ALDO2, .name = "aldo2", .enable_reg = AXP_POWERCTL3, .enable_mask = (uint8_t) AXP_POWERCTL3_ALDO2, .enable_value = AXP_POWERCTL3_ALDO2, .voltage_min = 700, .voltage_max = 3300, .voltage_step1 = 100, .voltage_nstep1 = 26, }, { .id = AXP8XX_REG_ID_ALDO3, .name = "aldo3", .enable_reg = AXP_POWERCTL3, .enable_mask = (uint8_t) AXP_POWERCTL3_ALDO3, .enable_value = AXP_POWERCTL3_ALDO3, .voltage_min = 700, .voltage_max = 3300, .voltage_step1 = 100, .voltage_nstep1 = 26, }, { .id = AXP8XX_REG_ID_ELDO1, .name = "eldo1", .enable_reg = AXP_POWERCTL2, .enable_mask = (uint8_t) AXP_POWERCTL2_ELDO1, .enable_value = AXP_POWERCTL2_ELDO1, .voltage_min = 700, .voltage_max = 1900, .voltage_step1 = 50, .voltage_nstep1 = 24, }, { .id = AXP8XX_REG_ID_ELDO2, .name = "eldo2", .enable_reg = AXP_POWERCTL2, .enable_mask = (uint8_t) AXP_POWERCTL2_ELDO2, .enable_value = AXP_POWERCTL2_ELDO2, .voltage_min = 700, .voltage_max = 1900, .voltage_step1 = 50, .voltage_nstep1 = 24, }, { .id = AXP8XX_REG_ID_ELDO3, .name = "eldo3", .enable_reg = AXP_POWERCTL2, .enable_mask = (uint8_t) AXP_POWERCTL2_ELDO3, .enable_value = AXP_POWERCTL2_ELDO3, .voltage_min = 700, .voltage_max = 1900, .voltage_step1 = 50, .voltage_nstep1 = 24, }, { .id = AXP8XX_REG_ID_FLDO1, .name = "fldo1", .enable_reg = AXP_POWERCTL3, .enable_mask = (uint8_t) AXP_POWERCTL3_FLDO1, .enable_value = AXP_POWERCTL3_FLDO1, .voltage_min = 700, .voltage_max = 1450, .voltage_step1 = 50, .voltage_nstep1 = 15, }, { .id = AXP8XX_REG_ID_FLDO2, .name = "fldo2", .enable_reg = AXP_POWERCTL3, .enable_mask = (uint8_t) AXP_POWERCTL3_FLDO2, .enable_value = AXP_POWERCTL3_FLDO2, .voltage_min = 700, .voltage_max = 1450, .voltage_step1 = 50, .voltage_nstep1 = 15, }, { .id = AXP8XX_REG_ID_GPIO0_LDO, .name = "ldo-io0", .enable_reg = AXP_GPIO0_CTRL, .enable_mask = (uint8_t) AXP_GPIO_FUNC, .enable_value = AXP_GPIO_FUNC_LDO_ON, .disable_value = AXP_GPIO_FUNC_LDO_OFF, .voltage_reg = AXP_GPIO0LDO_CTRL, .voltage_min = 700, .voltage_max = 3300, .voltage_step1 = 100, .voltage_nstep1 = 26, }, { .id = AXP8XX_REG_ID_GPIO1_LDO, .name = "ldo-io1", .enable_reg = AXP_GPIO1_CTRL, .enable_mask = (uint8_t) AXP_GPIO_FUNC, .enable_value = AXP_GPIO_FUNC_LDO_ON, .disable_value = AXP_GPIO_FUNC_LDO_OFF, .voltage_reg = AXP_GPIO1LDO_CTRL, .voltage_min = 700, .voltage_max = 3300, .voltage_step1 = 100, .voltage_nstep1 = 26, }, }; enum axp8xx_sensor { AXP_SENSOR_ACIN_PRESENT, AXP_SENSOR_VBUS_PRESENT, AXP_SENSOR_BATT_PRESENT, AXP_SENSOR_BATT_CHARGING, AXP_SENSOR_BATT_CHARGE_STATE, AXP_SENSOR_BATT_VOLTAGE, AXP_SENSOR_BATT_CHARGE_CURRENT, AXP_SENSOR_BATT_DISCHARGE_CURRENT, AXP_SENSOR_BATT_CAPACITY_PERCENT, AXP_SENSOR_BATT_MAXIMUM_CAPACITY, AXP_SENSOR_BATT_CURRENT_CAPACITY, }; enum battery_capacity_state { BATT_CAPACITY_NORMAL = 1, /* normal cap in battery */ BATT_CAPACITY_WARNING, /* warning cap in battery */ BATT_CAPACITY_CRITICAL, /* critical cap in battery */ BATT_CAPACITY_HIGH, /* high cap in battery */ BATT_CAPACITY_MAX, /* maximum cap in battery */ BATT_CAPACITY_LOW /* low cap in battery */ }; struct axp8xx_sensors { int id; const char *name; const char *desc; const char *format; }; static const struct axp8xx_sensors axp8xx_common_sensors[] = { { .id = AXP_SENSOR_ACIN_PRESENT, .name = "acin", .format = "I", .desc = "ACIN Present", }, { .id = AXP_SENSOR_VBUS_PRESENT, .name = "vbus", .format = "I", .desc = "VBUS Present", }, { .id = AXP_SENSOR_BATT_PRESENT, .name = "bat", .format = "I", .desc = "Battery Present", }, { .id = AXP_SENSOR_BATT_CHARGING, .name = "batcharging", .format = "I", .desc = "Battery Charging", }, { .id = AXP_SENSOR_BATT_CHARGE_STATE, .name = "batchargestate", .format = "I", .desc = "Battery Charge State", }, { .id = AXP_SENSOR_BATT_VOLTAGE, .name = "batvolt", .format = "I", .desc = "Battery Voltage", }, { .id = AXP_SENSOR_BATT_CHARGE_CURRENT, .name = "batchargecurrent", .format = "I", .desc = "Average Battery Charging Current", }, { .id = AXP_SENSOR_BATT_DISCHARGE_CURRENT, .name = "batdischargecurrent", .format = "I", .desc = "Average Battery Discharging Current", }, { .id = AXP_SENSOR_BATT_CAPACITY_PERCENT, .name = "batcapacitypercent", .format = "I", .desc = "Battery Capacity Percentage", }, { .id = AXP_SENSOR_BATT_MAXIMUM_CAPACITY, .name = "batmaxcapacity", .format = "I", .desc = "Battery Maximum Capacity", }, { .id = AXP_SENSOR_BATT_CURRENT_CAPACITY, .name = "batcurrentcapacity", .format = "I", .desc = "Battery Current Capacity", }, }; struct axp8xx_config { const char *name; int batsense_step; /* uV */ int charge_step; /* uA */ int discharge_step; /* uA */ int maxcap_step; /* uAh */ int coulomb_step; /* uAh */ }; static struct axp8xx_config axp803_config = { .name = "AXP803", .batsense_step = 1100, .charge_step = 1000, .discharge_step = 1000, .maxcap_step = 1456, .coulomb_step = 1456, }; struct axp8xx_softc; struct axp8xx_reg_sc { struct regnode *regnode; device_t base_dev; struct axp8xx_regdef *def; phandle_t xref; struct regnode_std_param *param; }; struct axp8xx_softc { struct resource *res; uint16_t addr; void *ih; device_t gpiodev; struct mtx mtx; int busy; int type; /* Configs */ const struct axp8xx_config *config; /* Sensors */ const struct axp8xx_sensors *sensors; int nsensors; /* Regulators */ struct axp8xx_reg_sc **regs; int nregs; /* Warning, shutdown thresholds */ int warn_thres; int shut_thres; }; #define AXP_LOCK(sc) mtx_lock(&(sc)->mtx) #define AXP_UNLOCK(sc) mtx_unlock(&(sc)->mtx) static int axp8xx_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size) { struct axp8xx_softc *sc; struct iic_msg msg[2]; sc = device_get_softc(dev); msg[0].slave = sc->addr; msg[0].flags = IIC_M_WR; msg[0].len = 1; msg[0].buf = ® msg[1].slave = sc->addr; msg[1].flags = IIC_M_RD; msg[1].len = size; msg[1].buf = data; return (iicbus_transfer(dev, msg, 2)); } static int axp8xx_write(device_t dev, uint8_t reg, uint8_t val) { struct axp8xx_softc *sc; struct iic_msg msg[2]; sc = device_get_softc(dev); msg[0].slave = sc->addr; msg[0].flags = IIC_M_WR; msg[0].len = 1; msg[0].buf = ® msg[1].slave = sc->addr; msg[1].flags = IIC_M_WR; msg[1].len = 1; msg[1].buf = &val; return (iicbus_transfer(dev, msg, 2)); } static int axp8xx_regnode_enable(struct regnode *regnode, bool enable, int *udelay) { struct axp8xx_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); if (bootverbose) device_printf(sc->base_dev, "%sable %s (%s)\n", enable ? "En" : "Dis", regnode_get_name(regnode), sc->def->name); axp8xx_read(sc->base_dev, sc->def->enable_reg, &val, 1); val &= ~sc->def->enable_mask; if (enable) val |= sc->def->enable_value; else { if (sc->def->disable_value) val |= sc->def->disable_value; else val &= ~sc->def->enable_value; } axp8xx_write(sc->base_dev, sc->def->enable_reg, val); *udelay = 0; return (0); } static void axp8xx_regnode_reg_to_voltage(struct axp8xx_reg_sc *sc, uint8_t val, int *uv) { if (val < sc->def->voltage_nstep1) *uv = sc->def->voltage_min + val * sc->def->voltage_step1; else *uv = sc->def->voltage_min + (sc->def->voltage_nstep1 * sc->def->voltage_step1) + ((val - sc->def->voltage_nstep1) * sc->def->voltage_step2); *uv *= 1000; } static int axp8xx_regnode_voltage_to_reg(struct axp8xx_reg_sc *sc, int min_uvolt, int max_uvolt, uint8_t *val) { uint8_t nval; int nstep, uvolt; nval = 0; uvolt = sc->def->voltage_min * 1000; for (nstep = 0; nstep < sc->def->voltage_nstep1 && uvolt < min_uvolt; nstep++) { ++nval; uvolt += (sc->def->voltage_step1 * 1000); } for (nstep = 0; nstep < sc->def->voltage_nstep2 && uvolt < min_uvolt; nstep++) { ++nval; uvolt += (sc->def->voltage_step2 * 1000); } if (uvolt > max_uvolt) return (EINVAL); *val = nval; return (0); } static int axp8xx_regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay) { struct axp8xx_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); if (bootverbose) device_printf(sc->base_dev, "Setting %s (%s) to %d<->%d\n", regnode_get_name(regnode), sc->def->name, min_uvolt, max_uvolt); if (sc->def->voltage_step1 == 0) return (ENXIO); if (axp8xx_regnode_voltage_to_reg(sc, min_uvolt, max_uvolt, &val) != 0) return (ERANGE); axp8xx_write(sc->base_dev, sc->def->voltage_reg, val); *udelay = 0; return (0); } static int axp8xx_regnode_get_voltage(struct regnode *regnode, int *uvolt) { struct axp8xx_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); if (!sc->def->voltage_step1 || !sc->def->voltage_step2) return (ENXIO); axp8xx_read(sc->base_dev, sc->def->voltage_reg, &val, 1); axp8xx_regnode_reg_to_voltage(sc, val & AXP_VOLTCTL_MASK, uvolt); return (0); } static regnode_method_t axp8xx_regnode_methods[] = { /* Regulator interface */ REGNODEMETHOD(regnode_enable, axp8xx_regnode_enable), REGNODEMETHOD(regnode_set_voltage, axp8xx_regnode_set_voltage), REGNODEMETHOD(regnode_get_voltage, axp8xx_regnode_get_voltage), REGNODEMETHOD(regnode_check_voltage, regnode_method_check_voltage), REGNODEMETHOD_END }; DEFINE_CLASS_1(axp8xx_regnode, axp8xx_regnode_class, axp8xx_regnode_methods, sizeof(struct axp8xx_reg_sc), regnode_class); static void axp8xx_shutdown(void *devp, int howto) { device_t dev; if ((howto & RB_POWEROFF) == 0) return; dev = devp; if (bootverbose) device_printf(dev, "Shutdown Axp8xx\n"); axp8xx_write(dev, AXP_POWERBAT, AXP_POWERBAT_SHUTDOWN); } static int axp8xx_sysctl_chargecurrent(SYSCTL_HANDLER_ARGS) { device_t dev = arg1; uint8_t data; int val, error; error = axp8xx_read(dev, AXP_CHARGERCTL1, &data, 1); if (error != 0) return (error); if (bootverbose) device_printf(dev, "Raw CHARGECTL1 val: 0x%0x\n", data); val = (data & AXP_CHARGERCTL1_CMASK); error = sysctl_handle_int(oidp, &val, 0, req); if (error || !req->newptr) /* error || read request */ return (error); if ((val < AXP_CHARGERCTL1_MIN) || (val > AXP_CHARGERCTL1_MAX)) return (EINVAL); val |= (data & (AXP_CHARGERCTL1_CMASK << 4)); axp8xx_write(dev, AXP_CHARGERCTL1, val); return (0); } static int axp8xx_sysctl(SYSCTL_HANDLER_ARGS) { struct axp8xx_softc *sc; device_t dev = arg1; enum axp8xx_sensor sensor = arg2; const struct axp8xx_config *c; uint8_t data; int val, i, found, batt_val; uint8_t lo, hi; sc = device_get_softc(dev); c = sc->config; for (found = 0, i = 0; i < sc->nsensors; i++) { if (sc->sensors[i].id == sensor) { found = 1; break; } } if (found == 0) return (ENOENT); switch (sensor) { case AXP_SENSOR_ACIN_PRESENT: if (axp8xx_read(dev, AXP_POWERSRC, &data, 1) == 0) val = !!(data & AXP_POWERSRC_ACIN); break; case AXP_SENSOR_VBUS_PRESENT: if (axp8xx_read(dev, AXP_POWERSRC, &data, 1) == 0) val = !!(data & AXP_POWERSRC_VBUS); break; case AXP_SENSOR_BATT_PRESENT: if (axp8xx_read(dev, AXP_POWERMODE, &data, 1) == 0) { if (data & AXP_POWERMODE_BAT_VALID) val = !!(data & AXP_POWERMODE_BAT_PRESENT); } break; case AXP_SENSOR_BATT_CHARGING: if (axp8xx_read(dev, AXP_POWERMODE, &data, 1) == 0) val = !!(data & AXP_POWERMODE_BAT_CHARGING); break; case AXP_SENSOR_BATT_CHARGE_STATE: if (axp8xx_read(dev, AXP_BAT_CAP, &data, 1) == 0 && (data & AXP_BAT_CAP_VALID) != 0) { batt_val = (data & AXP_BAT_CAP_PERCENT); if (batt_val <= sc->shut_thres) val = BATT_CAPACITY_CRITICAL; else if (batt_val <= sc->warn_thres) val = BATT_CAPACITY_WARNING; else val = BATT_CAPACITY_NORMAL; } break; case AXP_SENSOR_BATT_CAPACITY_PERCENT: if (axp8xx_read(dev, AXP_BAT_CAP, &data, 1) == 0 && (data & AXP_BAT_CAP_VALID) != 0) val = (data & AXP_BAT_CAP_PERCENT); break; case AXP_SENSOR_BATT_VOLTAGE: if (axp8xx_read(dev, AXP_BATSENSE_HI, &hi, 1) == 0 && axp8xx_read(dev, AXP_BATSENSE_LO, &lo, 1) == 0) { val = (AXP_SENSOR_BAT_H(hi) | AXP_SENSOR_BAT_L(lo)); val *= c->batsense_step; } break; case AXP_SENSOR_BATT_CHARGE_CURRENT: if (axp8xx_read(dev, AXP_POWERSRC, &data, 1) == 0 && (data & AXP_POWERSRC_CHARING) != 0 && axp8xx_read(dev, AXP_BATCHG_HI, &hi, 1) == 0 && axp8xx_read(dev, AXP_BATCHG_LO, &lo, 1) == 0) { val = (AXP_SENSOR_BAT_H(hi) | AXP_SENSOR_BAT_L(lo)); val *= c->charge_step; } break; case AXP_SENSOR_BATT_DISCHARGE_CURRENT: if (axp8xx_read(dev, AXP_POWERSRC, &data, 1) == 0 && (data & AXP_POWERSRC_CHARING) == 0 && axp8xx_read(dev, AXP_BATDISCHG_HI, &hi, 1) == 0 && axp8xx_read(dev, AXP_BATDISCHG_LO, &lo, 1) == 0) { val = (AXP_SENSOR_BAT_H(hi) | AXP_SENSOR_BAT_L(lo)); val *= c->discharge_step; } break; case AXP_SENSOR_BATT_MAXIMUM_CAPACITY: if (axp8xx_read(dev, AXP_BAT_MAX_CAP_HI, &hi, 1) == 0 && axp8xx_read(dev, AXP_BAT_MAX_CAP_LO, &lo, 1) == 0) { val = AXP_SENSOR_COULOMB(hi, lo); val *= c->maxcap_step; } break; case AXP_SENSOR_BATT_CURRENT_CAPACITY: if (axp8xx_read(dev, AXP_BAT_COULOMB_HI, &hi, 1) == 0 && axp8xx_read(dev, AXP_BAT_COULOMB_LO, &lo, 1) == 0) { val = AXP_SENSOR_COULOMB(hi, lo); val *= c->coulomb_step; } break; } return sysctl_handle_opaque(oidp, &val, sizeof(val), req); } static void axp8xx_intr(void *arg) { device_t dev; uint8_t val; int error; dev = arg; error = axp8xx_read(dev, AXP_IRQSTAT1, &val, 1); if (error != 0) return; if (val) { if (bootverbose) device_printf(dev, "AXP_IRQSTAT1 val: %x\n", val); if (val & AXP_IRQSTAT1_ACIN_HI) devctl_notify("PMU", "AC", "plugged", NULL); if (val & AXP_IRQSTAT1_ACIN_LO) devctl_notify("PMU", "AC", "unplugged", NULL); if (val & AXP_IRQSTAT1_VBUS_HI) devctl_notify("PMU", "USB", "plugged", NULL); if (val & AXP_IRQSTAT1_VBUS_LO) devctl_notify("PMU", "USB", "unplugged", NULL); /* Acknowledge */ axp8xx_write(dev, AXP_IRQSTAT1, val); } error = axp8xx_read(dev, AXP_IRQSTAT2, &val, 1); if (error != 0) return; if (val) { if (bootverbose) device_printf(dev, "AXP_IRQSTAT2 val: %x\n", val); if (val & AXP_IRQSTAT2_BATCHGD) devctl_notify("PMU", "Battery", "charged", NULL); if (val & AXP_IRQSTAT2_BATCHGC) devctl_notify("PMU", "Battery", "charging", NULL); if (val & AXP_IRQSTAT2_BAT_NO) devctl_notify("PMU", "Battery", "absent", NULL); if (val & AXP_IRQSTAT2_BAT_IN) devctl_notify("PMU", "Battery", "plugged", NULL); /* Acknowledge */ axp8xx_write(dev, AXP_IRQSTAT2, val); } error = axp8xx_read(dev, AXP_IRQSTAT3, &val, 1); if (error != 0) return; if (val) { /* Acknowledge */ axp8xx_write(dev, AXP_IRQSTAT3, val); } error = axp8xx_read(dev, AXP_IRQSTAT4, &val, 1); if (error != 0) return; if (val) { if (bootverbose) device_printf(dev, "AXP_IRQSTAT4 val: %x\n", val); if (val & AXP_IRQSTAT4_BATLVL_LO0) devctl_notify("PMU", "Battery", "shutdown threshold", NULL); if (val & AXP_IRQSTAT4_BATLVL_LO1) devctl_notify("PMU", "Battery", "warning threshold", NULL); /* Acknowledge */ axp8xx_write(dev, AXP_IRQSTAT4, val); } error = axp8xx_read(dev, AXP_IRQSTAT5, &val, 1); if (error != 0) return; if (val != 0) { if ((val & AXP_IRQSTAT5_POKSIRQ) != 0) { if (bootverbose) device_printf(dev, "Power button pressed\n"); shutdown_nice(RB_POWEROFF); } /* Acknowledge */ axp8xx_write(dev, AXP_IRQSTAT5, val); } error = axp8xx_read(dev, AXP_IRQSTAT6, &val, 1); if (error != 0) return; if (val) { /* Acknowledge */ axp8xx_write(dev, AXP_IRQSTAT6, val); } } static device_t axp8xx_gpio_get_bus(device_t dev) { struct axp8xx_softc *sc; sc = device_get_softc(dev); return (sc->gpiodev); } static int axp8xx_gpio_pin_max(device_t dev, int *maxpin) { *maxpin = nitems(axp8xx_pins) - 1; return (0); } static int axp8xx_gpio_pin_getname(device_t dev, uint32_t pin, char *name) { if (pin >= nitems(axp8xx_pins)) return (EINVAL); snprintf(name, GPIOMAXNAME, "%s", axp8xx_pins[pin].name); return (0); } static int axp8xx_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) { if (pin >= nitems(axp8xx_pins)) return (EINVAL); *caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT; return (0); } static int axp8xx_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) { struct axp8xx_softc *sc; uint8_t data, func; int error; if (pin >= nitems(axp8xx_pins)) return (EINVAL); sc = device_get_softc(dev); AXP_LOCK(sc); error = axp8xx_read(dev, axp8xx_pins[pin].ctrl_reg, &data, 1); if (error == 0) { func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT; if (func == AXP_GPIO_FUNC_INPUT) *flags = GPIO_PIN_INPUT; else if (func == AXP_GPIO_FUNC_DRVLO || func == AXP_GPIO_FUNC_DRVHI) *flags = GPIO_PIN_OUTPUT; else *flags = 0; } AXP_UNLOCK(sc); return (error); } static int axp8xx_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) { struct axp8xx_softc *sc; uint8_t data; int error; if (pin >= nitems(axp8xx_pins)) return (EINVAL); sc = device_get_softc(dev); AXP_LOCK(sc); error = axp8xx_read(dev, axp8xx_pins[pin].ctrl_reg, &data, 1); if (error == 0) { data &= ~AXP_GPIO_FUNC; if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) != 0) { if ((flags & GPIO_PIN_OUTPUT) == 0) data |= AXP_GPIO_FUNC_INPUT; } error = axp8xx_write(dev, axp8xx_pins[pin].ctrl_reg, data); } AXP_UNLOCK(sc); return (error); } static int axp8xx_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) { struct axp8xx_softc *sc; uint8_t data, func; int error; if (pin >= nitems(axp8xx_pins)) return (EINVAL); sc = device_get_softc(dev); AXP_LOCK(sc); error = axp8xx_read(dev, axp8xx_pins[pin].ctrl_reg, &data, 1); if (error == 0) { func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT; switch (func) { case AXP_GPIO_FUNC_DRVLO: *val = 0; break; case AXP_GPIO_FUNC_DRVHI: *val = 1; break; case AXP_GPIO_FUNC_INPUT: error = axp8xx_read(dev, AXP_GPIO_SIGBIT, &data, 1); if (error == 0) *val = (data & (1 << pin)) ? 1 : 0; break; default: error = EIO; break; } } AXP_UNLOCK(sc); return (error); } static int axp8xx_gpio_pin_set(device_t dev, uint32_t pin, unsigned int val) { struct axp8xx_softc *sc; uint8_t data, func; int error; if (pin >= nitems(axp8xx_pins)) return (EINVAL); sc = device_get_softc(dev); AXP_LOCK(sc); error = axp8xx_read(dev, axp8xx_pins[pin].ctrl_reg, &data, 1); if (error == 0) { func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT; switch (func) { case AXP_GPIO_FUNC_DRVLO: case AXP_GPIO_FUNC_DRVHI: data &= ~AXP_GPIO_FUNC; data |= (val << AXP_GPIO_FUNC_SHIFT); break; default: error = EIO; break; } } if (error == 0) error = axp8xx_write(dev, axp8xx_pins[pin].ctrl_reg, data); AXP_UNLOCK(sc); return (error); } static int axp8xx_gpio_pin_toggle(device_t dev, uint32_t pin) { struct axp8xx_softc *sc; uint8_t data, func; int error; if (pin >= nitems(axp8xx_pins)) return (EINVAL); sc = device_get_softc(dev); AXP_LOCK(sc); error = axp8xx_read(dev, axp8xx_pins[pin].ctrl_reg, &data, 1); if (error == 0) { func = (data & AXP_GPIO_FUNC) >> AXP_GPIO_FUNC_SHIFT; switch (func) { case AXP_GPIO_FUNC_DRVLO: data &= ~AXP_GPIO_FUNC; data |= (AXP_GPIO_FUNC_DRVHI << AXP_GPIO_FUNC_SHIFT); break; case AXP_GPIO_FUNC_DRVHI: data &= ~AXP_GPIO_FUNC; data |= (AXP_GPIO_FUNC_DRVLO << AXP_GPIO_FUNC_SHIFT); break; default: error = EIO; break; } } if (error == 0) error = axp8xx_write(dev, axp8xx_pins[pin].ctrl_reg, data); AXP_UNLOCK(sc); return (error); } static int axp8xx_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent, int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags) { if (gpios[0] >= nitems(axp8xx_pins)) return (EINVAL); *pin = gpios[0]; *flags = gpios[1]; return (0); } static phandle_t axp8xx_get_node(device_t dev, device_t bus) { return (ofw_bus_get_node(dev)); } static struct axp8xx_reg_sc * axp8xx_reg_attach(device_t dev, phandle_t node, struct axp8xx_regdef *def) { struct axp8xx_reg_sc *reg_sc; struct regnode_init_def initdef; struct regnode *regnode; memset(&initdef, 0, sizeof(initdef)); if (regulator_parse_ofw_stdparam(dev, node, &initdef) != 0) return (NULL); if (initdef.std_param.min_uvolt == 0) initdef.std_param.min_uvolt = def->voltage_min * 1000; if (initdef.std_param.max_uvolt == 0) initdef.std_param.max_uvolt = def->voltage_max * 1000; initdef.id = def->id; initdef.ofw_node = node; regnode = regnode_create(dev, &axp8xx_regnode_class, &initdef); if (regnode == NULL) { device_printf(dev, "cannot create regulator\n"); return (NULL); } reg_sc = regnode_get_softc(regnode); reg_sc->regnode = regnode; reg_sc->base_dev = dev; reg_sc->def = def; reg_sc->xref = OF_xref_from_node(node); reg_sc->param = regnode_get_stdparam(regnode); regnode_register(regnode); return (reg_sc); } static int axp8xx_regdev_map(device_t dev, phandle_t xref, int ncells, pcell_t *cells, intptr_t *num) { struct axp8xx_softc *sc; int i; sc = device_get_softc(dev); for (i = 0; i < sc->nregs; i++) { if (sc->regs[i] == NULL) continue; if (sc->regs[i]->xref == xref) { *num = sc->regs[i]->def->id; return (0); } } return (ENXIO); } static int axp8xx_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) { case AXP803: device_set_desc(dev, "X-Powers AXP803 Power Management Unit"); break; case AXP813: device_set_desc(dev, "X-Powers AXP813 Power Management Unit"); break; default: return (ENXIO); } return (BUS_PROBE_DEFAULT); } static int axp8xx_attach(device_t dev) { struct axp8xx_softc *sc; struct axp8xx_reg_sc *reg; uint8_t chip_id, val; phandle_t rnode, child; int error, i; sc = device_get_softc(dev); sc->addr = iicbus_get_addr(dev); mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); error = bus_alloc_resources(dev, axp8xx_spec, &sc->res); if (error != 0) { device_printf(dev, "cannot allocate resources for device\n"); return (error); } if (bootverbose) { axp8xx_read(dev, AXP_ICTYPE, &chip_id, 1); device_printf(dev, "chip ID 0x%02x\n", chip_id); } sc->nregs = nitems(axp8xx_common_regdefs); sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; switch (sc->type) { case AXP803: sc->nregs += nitems(axp803_regdefs); break; case AXP813: sc->nregs += nitems(axp813_regdefs); break; } sc->config = &axp803_config; sc->sensors = axp8xx_common_sensors; sc->nsensors = nitems(axp8xx_common_sensors); sc->regs = malloc(sizeof(struct axp8xx_reg_sc *) * sc->nregs, M_AXP8XX_REG, M_WAITOK | M_ZERO); /* Attach known regulators that exist in the DT */ rnode = ofw_bus_find_child(ofw_bus_get_node(dev), "regulators"); if (rnode > 0) { for (i = 0; i < sc->nregs; i++) { char *regname; struct axp8xx_regdef *regdef; if (i <= nitems(axp8xx_common_regdefs)) { regname = axp8xx_common_regdefs[i].name; regdef = &axp8xx_common_regdefs[i]; } else { int off; off = i - nitems(axp8xx_common_regdefs); switch (sc->type) { case AXP803: regname = axp803_regdefs[off].name; regdef = &axp803_regdefs[off]; break; case AXP813: regname = axp813_regdefs[off].name; regdef = &axp813_regdefs[off]; break; } } child = ofw_bus_find_child(rnode, regname); if (child == 0) continue; reg = axp8xx_reg_attach(dev, child, regdef); if (reg == NULL) { device_printf(dev, "cannot attach regulator %s\n", regname); continue; } sc->regs[i] = reg; } } /* Add sensors */ for (i = 0; i < sc->nsensors; i++) { SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, sc->sensors[i].name, CTLTYPE_INT | CTLFLAG_RD, dev, sc->sensors[i].id, axp8xx_sysctl, sc->sensors[i].format, sc->sensors[i].desc); } SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "batchargecurrentstep", CTLTYPE_INT | CTLFLAG_RW, dev, 0, axp8xx_sysctl_chargecurrent, "I", "Battery Charging Current Step, " "0: 200mA, 1: 400mA, 2: 600mA, 3: 800mA, " "4: 1000mA, 5: 1200mA, 6: 1400mA, 7: 1600mA, " "8: 1800mA, 9: 2000mA, 10: 2200mA, 11: 2400mA, " "12: 2600mA, 13: 2800mA"); /* Get thresholds */ if (axp8xx_read(dev, AXP_BAT_CAP_WARN, &val, 1) == 0) { sc->warn_thres = (val & AXP_BAT_CAP_WARN_LV1) >> 4; sc->warn_thres += AXP_BAP_CAP_WARN_LV1BASE; sc->shut_thres = (val & AXP_BAT_CAP_WARN_LV2); if (bootverbose) { device_printf(dev, "Raw reg val: 0x%02x\n", val); device_printf(dev, "Warning threshold: 0x%02x\n", sc->warn_thres); device_printf(dev, "Shutdown threshold: 0x%02x\n", sc->shut_thres); } } /* Enable interrupts */ axp8xx_write(dev, AXP_IRQEN1, AXP_IRQEN1_VBUS_LO | AXP_IRQEN1_VBUS_HI | AXP_IRQEN1_ACIN_LO | AXP_IRQEN1_ACIN_HI); axp8xx_write(dev, AXP_IRQEN2, AXP_IRQEN2_BATCHGD | AXP_IRQEN2_BATCHGC | AXP_IRQEN2_BAT_NO | AXP_IRQEN2_BAT_IN); axp8xx_write(dev, AXP_IRQEN3, 0); axp8xx_write(dev, AXP_IRQEN4, AXP_IRQEN4_BATLVL_LO0 | AXP_IRQEN4_BATLVL_LO1); axp8xx_write(dev, AXP_IRQEN5, AXP_IRQEN5_POKSIRQ | AXP_IRQEN5_POKLIRQ); axp8xx_write(dev, AXP_IRQEN6, 0); /* Install interrupt handler */ error = bus_setup_intr(dev, sc->res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, axp8xx_intr, dev, &sc->ih); if (error != 0) { device_printf(dev, "cannot setup interrupt handler\n"); return (error); } EVENTHANDLER_REGISTER(shutdown_final, axp8xx_shutdown, dev, SHUTDOWN_PRI_LAST); sc->gpiodev = gpiobus_attach_bus(dev); return (0); } static device_method_t axp8xx_methods[] = { /* Device interface */ DEVMETHOD(device_probe, axp8xx_probe), DEVMETHOD(device_attach, axp8xx_attach), /* GPIO interface */ DEVMETHOD(gpio_get_bus, axp8xx_gpio_get_bus), DEVMETHOD(gpio_pin_max, axp8xx_gpio_pin_max), DEVMETHOD(gpio_pin_getname, axp8xx_gpio_pin_getname), DEVMETHOD(gpio_pin_getcaps, axp8xx_gpio_pin_getcaps), DEVMETHOD(gpio_pin_getflags, axp8xx_gpio_pin_getflags), DEVMETHOD(gpio_pin_setflags, axp8xx_gpio_pin_setflags), DEVMETHOD(gpio_pin_get, axp8xx_gpio_pin_get), DEVMETHOD(gpio_pin_set, axp8xx_gpio_pin_set), DEVMETHOD(gpio_pin_toggle, axp8xx_gpio_pin_toggle), DEVMETHOD(gpio_map_gpios, axp8xx_gpio_map_gpios), /* Regdev interface */ DEVMETHOD(regdev_map, axp8xx_regdev_map), /* OFW bus interface */ DEVMETHOD(ofw_bus_get_node, axp8xx_get_node), DEVMETHOD_END }; static driver_t axp8xx_driver = { "axp8xx_pmu", axp8xx_methods, sizeof(struct axp8xx_softc), }; static devclass_t axp8xx_devclass; extern devclass_t ofwgpiobus_devclass, gpioc_devclass; extern driver_t ofw_gpiobus_driver, gpioc_driver; EARLY_DRIVER_MODULE(axp8xx, iicbus, axp8xx_driver, axp8xx_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); EARLY_DRIVER_MODULE(ofw_gpiobus, axp8xx_pmu, ofw_gpiobus_driver, ofwgpiobus_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); DRIVER_MODULE(gpioc, axp8xx_pmu, gpioc_driver, gpioc_devclass, 0, 0); MODULE_VERSION(axp8xx, 1); MODULE_DEPEND(axp8xx, iicbus, 1, 1, 1); SIMPLEBUS_PNP_INFO(compat_data); Index: head/sys/arm/allwinner/clkng/aw_clk.h =================================================================== --- head/sys/arm/allwinner/clkng/aw_clk.h (revision 355356) +++ head/sys/arm/allwinner/clkng/aw_clk.h (revision 355357) @@ -1,605 +1,604 @@ /*- * Copyright (c) 2017 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef __AW_CLK_H__ #define __AW_CLK_H__ /* Allwinner clocks formula : PLLs: (24MHz*N*K)/(M*P) (24MHz*N)/(M*P) (24MHz*N*2)/M (24MHz*N)/M (24MHz*N*K)/M (24MHz*N*K/2) (24MHz*N)/M (24MHz*N*K/2) (24MHz*N)/M Periph clocks: Clock Source/Divider N/Divider M Clock Source/Divider N/Divider M/2 Clock Source*N/(Divider M+1)/(Divider P+1) */ struct aw_clk_init { const char *name; const char *parent_name; uint64_t default_freq; bool enable; }; #define AW_CLK_HAS_GATE 0x0001 #define AW_CLK_HAS_LOCK 0x0002 #define AW_CLK_HAS_MUX 0x0004 #define AW_CLK_REPARENT 0x0008 #define AW_CLK_SCALE_CHANGE 0x0010 #define AW_CLK_HAS_UPDATE 0x0040 #define AW_CLK_HAS_PREDIV 0x0080 #define AW_CLK_SET_PARENT 0x0100 #define AW_CLK_FACTOR_POWER_OF_TWO 0x0001 #define AW_CLK_FACTOR_ZERO_BASED 0x0002 #define AW_CLK_FACTOR_HAS_COND 0x0004 #define AW_CLK_FACTOR_FIXED 0x0008 #define AW_CLK_FACTOR_ZERO_IS_ONE 0x0010 #define AW_CLK_FACTOR_MIN_VALUE 0x0020 #define AW_CLK_FACTOR_MAX_VALUE 0x0040 struct aw_clk_factor { uint32_t shift; /* Shift bits for the factor */ uint32_t mask; /* Mask to get the factor, will be override by the clk methods */ uint32_t width; /* Number of bits for the factor */ uint32_t value; /* Fixed value, depends on AW_CLK_FACTOR_FIXED */ uint32_t cond_shift; uint32_t cond_mask; uint32_t cond_width; uint32_t cond_value; uint32_t min_value; uint32_t max_value; uint32_t flags; /* Flags */ }; struct aw_clk_frac { uint64_t freq0; uint64_t freq1; uint32_t mode_sel; uint32_t freq_sel; }; static inline uint32_t aw_clk_get_factor(uint32_t val, struct aw_clk_factor *factor) { uint32_t factor_val; uint32_t cond; if (factor->flags & AW_CLK_FACTOR_HAS_COND) { cond = (val & factor->cond_mask) >> factor->cond_shift; if (cond != factor->cond_value) return (1); } if (factor->flags & AW_CLK_FACTOR_FIXED) return (factor->value); factor_val = (val & factor->mask) >> factor->shift; if (factor_val == 0 && (factor->flags & AW_CLK_FACTOR_ZERO_IS_ONE)) factor_val = 1; if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO) factor_val = 1 << factor_val; else if (!(factor->flags & AW_CLK_FACTOR_ZERO_BASED)) factor_val += 1; return (factor_val); } static inline uint32_t aw_clk_factor_get_max(struct aw_clk_factor *factor) { uint32_t max; if (factor->flags & AW_CLK_FACTOR_FIXED) max = factor->value; else if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO) max = 1 << ((1 << factor->width) - 1); else { max = (1 << factor->width); } return (max); } static inline uint32_t aw_clk_factor_get_min(struct aw_clk_factor *factor) { uint32_t min; if (factor->flags & AW_CLK_FACTOR_FIXED) min = factor->value; else if (factor->flags & AW_CLK_FACTOR_ZERO_BASED) min = 0; else if (factor->flags & AW_CLK_FACTOR_MIN_VALUE) min = factor->min_value; else min = 1; return (min); } static inline uint32_t aw_clk_factor_get_value(struct aw_clk_factor *factor, uint32_t raw) { uint32_t val; if (factor->flags & AW_CLK_FACTOR_FIXED) return (factor->value); if (factor->flags & AW_CLK_FACTOR_ZERO_BASED) val = raw; else if (factor->flags & AW_CLK_FACTOR_POWER_OF_TWO) { for (val = 0; raw != 1; val++) raw >>= 1; } else if (factor->flags & AW_CLK_FACTOR_MAX_VALUE) val = factor->max_value; else val = raw - 1; return (val); } #define CCU_RESET(idx, o, s) \ [idx] = { \ .offset = o, \ .shift = s, \ }, #define CCU_GATE(idx, clkname, pname, o, s) \ [idx] = { \ .name = clkname, \ .parent_name = pname, \ .offset = o, \ .shift = s, \ }, #define NKMP_CLK(_clkname, _id, _name, _pnames, \ _offset, \ _n_shift, _n_width, _n_value, _n_flags, \ _k_shift, _k_width, _k_value, _k_flags, \ _m_shift, _m_width, _m_value, _m_flags, \ _p_shift, _p_width, _p_value, _p_flags, \ _gate, \ _lock, _lock_retries, \ _flags) \ static struct aw_clk_nkmp_def _clkname = { \ .clkdef = { \ .id = _id, \ .name = _name, \ .parent_names = _pnames, \ .parent_cnt = nitems(_pnames), \ }, \ .offset = _offset, \ .n.shift = _n_shift, \ .n.width = _n_width, \ .n.value = _n_value, \ .n.flags = _n_flags, \ .k.shift = _k_shift, \ .k.width = _k_width, \ .k.value = _k_value, \ .k.flags = _k_flags, \ .m.shift = _m_shift, \ .m.width = _m_width, \ .m.value = _m_value, \ .m.flags = _m_flags, \ .p.shift = _p_shift, \ .p.width = _p_width, \ .p.value = _p_value, \ .p.flags = _p_flags, \ .gate_shift = _gate, \ .lock_shift = _lock, \ .lock_retries = _lock_retries, \ .flags = _flags, \ } #define NKMP_CLK_WITH_MUX(_clkname, \ _id, _name, _pnames, \ _offset, \ _n_shift, _n_width, _n_value, _n_flags, \ _k_shift, _k_width, _k_value, _k_flags, \ _m_shift, _m_width, _m_value, _m_flags, \ _p_shift, _p_width, _p_value, _p_flags, \ _mux_shift, _mux_width, _gate, \ _lock, _lock_retries, \ _flags) \ static struct aw_clk_nkmp_def _clkname = { \ .clkdef = { \ .id = _id, \ .name = _name, \ .parent_names = _pnames, \ .parent_cnt = nitems(_pnames), \ }, \ .offset = _offset, \ .n.shift = _n_shift, \ .n.width = _n_width, \ .n.value = _n_value, \ .n.flags = _n_flags, \ .k.shift = _k_shift, \ .k.width = _k_width, \ .k.value = _k_value, \ .k.flags = _k_flags, \ .m.shift = _m_shift, \ .m.width = _m_width, \ .m.value = _m_value, \ .m.flags = _m_flags, \ .p.shift = _p_shift, \ .p.width = _p_width, \ .p.value = _p_value, \ .p.flags = _p_flags, \ .mux_shift = _mux_shift, \ .mux_width = _mux_width, \ .gate_shift = _gate, \ .lock_shift = _lock, \ .lock_retries = _lock_retries, \ .flags = _flags, \ } #define NKMP_CLK_WITH_UPDATE(_clkname, \ _id, _name, _pnames, \ _offset, \ _n_shift, _n_width, _n_value, _n_flags, \ _k_shift, _k_width, _k_value, _k_flags, \ _m_shift, _m_width, _m_value, _m_flags, \ _p_shift, _p_width, _p_value, _p_flags, \ _gate, \ _lock, _lock_retries, \ _update, \ _flags) \ static struct aw_clk_nkmp_def _clkname = { \ .clkdef = { \ .id = _id, \ .name = _name, \ .parent_names = _pnames, \ .parent_cnt = nitems(_pnames), \ }, \ .offset = _offset, \ .n.shift = _n_shift, \ .n.width = _n_width, \ .n.value = _n_value, \ .n.flags = _n_flags, \ .k.shift = _k_shift, \ .k.width = _k_width, \ .k.value = _k_value, \ .k.flags = _k_flags, \ .m.shift = _m_shift, \ .m.width = _m_width, \ .m.value = _m_value, \ .m.flags = _m_flags, \ .p.shift = _p_shift, \ .p.width = _p_width, \ .p.value = _p_value, \ .p.flags = _p_flags, \ .gate_shift = _gate, \ .lock_shift = _lock, \ .lock_retries = _lock_retries, \ .update_shift = _update, \ .flags = _flags | AW_CLK_HAS_UPDATE, \ } #define FRAC_CLK(_clkname, _id, _name, _pnames, \ _offset, \ _nshift, _nwidth, _nvalue, _nflags, \ _mshift, _mwidth, _mvalue, _mflags, \ _gate_shift, _lock_shift,_lock_retries, \ _flags, _freq0, _freq1, _mode_sel, _freq_sel, \ _min_freq, _max_freq) \ static struct aw_clk_frac_def _clkname = { \ .clkdef = { \ .id = _id, \ .name = _name, \ .parent_names = _pnames, \ .parent_cnt = nitems(_pnames), \ .flags = CLK_NODE_GLITCH_FREE, \ }, \ .offset = _offset, \ .n.shift = _nshift, \ .n.width = _nwidth, \ .n.value = _nvalue, \ .n.flags = _nflags, \ .m.shift = _mshift, \ .m.width = _mwidth, \ .m.value = _mvalue, \ .m.flags = _mflags, \ .gate_shift = _gate_shift, \ .lock_shift = _lock_shift, \ .lock_retries = _lock_retries, \ .flags = _flags, \ .frac.freq0 = _freq0, \ .frac.freq1 = _freq1, \ .frac.mode_sel = _mode_sel, \ .frac.freq_sel = _freq_sel, \ .min_freq = _min_freq, \ .max_freq = _max_freq, \ } #define M_CLK(_clkname, _id, _name, _pnames, \ _offset, \ _mshift, _mwidth, _mvalue, _mflags, \ _mux_shift, _mux_width, \ _gate_shift, \ _flags) \ static struct aw_clk_m_def _clkname = { \ .clkdef = { \ .id = _id, \ .name = _name, \ .parent_names = _pnames, \ .parent_cnt = nitems(_pnames), \ }, \ .offset = _offset, \ .mux_shift = _mux_shift, \ .m.shift = _mshift, \ .m.width = _mwidth, \ .m.value = _mvalue, \ .m.flags = _mflags, \ .mux_width = _mux_width, \ .gate_shift = _gate_shift, \ .flags = _flags, \ } #define NM_CLK(_clkname, _id, _name, _pnames, \ _offset, \ _nshift, _nwidth, _nvalue, _nflags, \ _mshift, _mwidth, _mvalue, _mflags, \ _mux_shift, _mux_width, \ _gate_shift, \ _flags) \ static struct aw_clk_nm_def _clkname = { \ .clkdef = { \ .id = _id, \ .name = _name, \ .parent_names = _pnames, \ .parent_cnt = nitems(_pnames), \ }, \ .offset = _offset, \ .n.shift = _nshift, \ .n.width = _nwidth, \ .n.value = _nvalue, \ .n.flags = _nflags, \ .mux_shift = _mux_shift, \ .m.shift = _mshift, \ .m.width = _mwidth, \ .m.value = _mvalue, \ .m.flags = _mflags, \ .mux_width = _mux_width, \ .gate_shift = _gate_shift, \ .flags = _flags, \ } #define NMM_CLK(_clkname, _id, _name, _pnames, \ _offset, \ _nshift, _nwidth, _nvalue, _nflags, \ _m0shift, _m0width, _m0value, _m0flags, \ _m1shift, _m1width, _m1value, _m1flags, \ _gate_shift, \ _lock, _lock_retries, \ _flags) \ static struct aw_clk_nmm_def _clkname = { \ .clkdef = { \ .id = _id, \ .name = _name, \ .parent_names = _pnames, \ .parent_cnt = nitems(_pnames), \ }, \ .offset = _offset, \ .n.shift = _nshift, \ .n.width = _nwidth, \ .n.value = _nvalue, \ .n.flags = _nflags, \ .m0.shift = _m0shift, \ .m0.width = _m0width, \ .m0.value = _m0value, \ .m0.flags = _m0flags, \ .m1.shift = _m1shift, \ .m1.width = _m1width, \ .m1.value = _m1value, \ .m1.flags = _m1flags, \ .gate_shift = _gate_shift, \ .lock_shift = _lock, \ .lock_retries = _lock_retries, \ .flags = _flags, \ } #define NP_CLK(_clkname, _id, _name, _pnames, \ _offset, \ _nshift, _nwidth, _nvalue, _nflags, \ _pshift, _pwidth, _pvalue, _pflags, \ _gate_shift, \ _lock, _lock_retries, \ _flags) \ static struct aw_clk_np_def _clkname = { \ .clkdef = { \ .id = _id, \ .name = _name, \ .parent_names = _pnames, \ .parent_cnt = nitems(_pnames), \ }, \ .offset = _offset, \ .n.shift = _nshift, \ .n.width = _nwidth, \ .n.value = _nvalue, \ .n.flags = _nflags, \ .p.shift = _pshift, \ .p.width = _pwidth, \ .p.value = _pvalue, \ .p.flags = _pflags, \ .gate_shift = _gate_shift, \ .lock_shift = _lock, \ .lock_retries = _lock_retries, \ .flags = _flags, \ } #define PREDIV_CLK(_clkname, _id, _name, _pnames, \ _offset, \ _mux_shift, _mux_width, \ _div_shift, _div_width, _div_value, _div_flags, \ _prediv_shift, _prediv_width, _prediv_value, _prediv_flags, \ _prediv_cond_shift, _prediv_cond_width, _prediv_cond_value) \ static struct aw_clk_prediv_mux_def _clkname = { \ .clkdef = { \ .id = _id, \ .name = _name, \ .parent_names = _pnames, \ .parent_cnt = nitems(_pnames), \ }, \ .offset = _offset, \ .mux_shift = _mux_shift, \ .mux_width = _mux_width, \ .div.shift = _div_shift, \ .div.width = _div_width, \ .div.value = _div_value, \ .div.flags = _div_flags, \ .prediv.shift = _prediv_shift, \ .prediv.width = _prediv_width, \ .prediv.value = _prediv_value, \ .prediv.flags = _prediv_flags, \ .prediv.cond_shift = _prediv_cond_shift, \ .prediv.cond_width = _prediv_cond_width, \ .prediv.cond_value = _prediv_cond_value, \ } #define PREDIV_CLK_WITH_MASK(_clkname, _id, _name, _pnames, \ _offset, \ _mux_shift, _mux_width, \ _div_shift, _div_width, _div_value, _div_flags, \ _prediv_shift, _prediv_width, _prediv_value, _prediv_flags, \ _prediv_cond_mask, _prediv_cond_value) \ static struct aw_clk_prediv_mux_def _clkname = { \ .clkdef = { \ .id = _id, \ .name = _name, \ .parent_names = _pnames, \ .parent_cnt = nitems(_pnames), \ }, \ .offset = _offset, \ .mux_shift = _mux_shift, \ .mux_width = _mux_width, \ .div.shift = _div_shift, \ .div.width = _div_width, \ .div.value = _div_value, \ .div.flags = _div_flags, \ .prediv.shift = _prediv_shift, \ .prediv.width = _prediv_width, \ .prediv.value = _prediv_value, \ .prediv.flags = _prediv_flags, \ .prediv.cond_shift = 0, \ .prediv.cond_width = 0, \ .prediv.cond_mask = _prediv_cond_mask, \ .prediv.cond_value = _prediv_cond_value, \ } #define MIPI_CLK(_clkname, _id, _name, _pnames, \ _offset, \ _kshift, _kwidth, _kflags, _kmin, \ _mshift, _mwidth, \ _nshift, _nwidth, \ _gate_shift, _lock_shift) \ static struct aw_clk_mipi_def _clkname = { \ .clkdef = { \ .id = _id, \ .name = _name, \ .parent_names = _pnames, \ .parent_cnt = nitems(_pnames) \ }, \ .offset = _offset, \ .k.shift = _kshift, \ .k.width = _kwidth, \ .k.flags = _kflags, \ .k.min_value = _kmin, \ .m.shift = _mshift, \ .m.width = _mwidth, \ .n.shift = _nshift, \ .n.width = _nwidth, \ .gate_shift = _gate_shift, \ .lock_shift = _lock_shift, \ } #define MUX_CLK(_clkname, _id, _name, _pnames, \ _offset, _shift, _width) \ static struct clk_mux_def _clkname = { \ .clkdef = { \ .id = _id, \ .name = _name, \ .parent_names = _pnames, \ .parent_cnt = nitems(_pnames) \ }, \ .offset = _offset, \ .shift = _shift, \ .width = _width, \ } #define DIV_CLK(_clkname, _id, _name, _pnames, \ _offset, \ _i_shift, _i_width, \ _div_flags, _div_table) \ static struct clk_div_def _clkname = { \ .clkdef = { \ .id = _id, \ .name = _name, \ .parent_names = _pnames, \ .parent_cnt = nitems(_pnames) \ }, \ .offset = _offset, \ .i_shift = _i_shift, \ .i_width = _i_width, \ .div_flags = _div_flags, \ .div_table = _div_table, \ } #define FIXED_CLK(_clkname, _id, _name, _pnames, \ _freq, _mult, _div, _flags) \ static struct clk_fixed_def _clkname = { \ .clkdef = { \ .id = _id, \ .name = _name, \ .parent_names = _pnames, \ .parent_cnt = 1, \ }, \ .freq = _freq, \ .mult = _mult, \ .div = _div, \ .fixed_flags = _flags, \ } #endif /* __AW_CLK_H__ */ Index: head/sys/arm/allwinner/clkng/aw_clk_nkmp.c =================================================================== --- head/sys/arm/allwinner/clkng/aw_clk_nkmp.c (revision 355356) +++ head/sys/arm/allwinner/clkng/aw_clk_nkmp.c (revision 355357) @@ -1,415 +1,414 @@ /*- * Copyright (c) 2017 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include "clkdev_if.h" /* * clknode for clocks matching the formula : * * clk = (clkin * n * k) / (m * p) * */ struct aw_clk_nkmp_sc { uint32_t offset; struct aw_clk_factor n; struct aw_clk_factor k; struct aw_clk_factor m; struct aw_clk_factor p; uint32_t mux_shift; uint32_t mux_mask; uint32_t gate_shift; uint32_t lock_shift; uint32_t lock_retries; uint32_t update_shift; uint32_t flags; }; #define WRITE4(_clk, off, val) \ CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) #define READ4(_clk, off, val) \ CLKDEV_READ_4(clknode_get_device(_clk), off, val) #define MODIFY4(_clk, off, clr, set ) \ CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set) #define DEVICE_LOCK(_clk) \ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) #define DEVICE_UNLOCK(_clk) \ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) static int aw_clk_nkmp_init(struct clknode *clk, device_t dev) { struct aw_clk_nkmp_sc *sc; uint32_t val, idx; sc = clknode_get_softc(clk); idx = 0; if ((sc->flags & AW_CLK_HAS_MUX) != 0) { DEVICE_LOCK(clk); READ4(clk, sc->offset, &val); DEVICE_UNLOCK(clk); idx = (val & sc->mux_mask) >> sc->mux_shift; } clknode_init_parent_idx(clk, idx); return (0); } static int aw_clk_nkmp_set_gate(struct clknode *clk, bool enable) { struct aw_clk_nkmp_sc *sc; uint32_t val; sc = clknode_get_softc(clk); if ((sc->flags & AW_CLK_HAS_GATE) == 0) return (0); DEVICE_LOCK(clk); READ4(clk, sc->offset, &val); if (enable) val |= (1 << sc->gate_shift); else val &= ~(1 << sc->gate_shift); WRITE4(clk, sc->offset, val); DEVICE_UNLOCK(clk); return (0); } static int aw_clk_nkmp_set_mux(struct clknode *clk, int index) { struct aw_clk_nkmp_sc *sc; uint32_t val; sc = clknode_get_softc(clk); if ((sc->flags & AW_CLK_HAS_MUX) == 0) return (0); DEVICE_LOCK(clk); READ4(clk, sc->offset, &val); val &= ~sc->mux_mask; val |= index << sc->mux_shift; WRITE4(clk, sc->offset, val); DEVICE_UNLOCK(clk); return (0); } static uint64_t aw_clk_nkmp_find_best(struct aw_clk_nkmp_sc *sc, uint64_t fparent, uint64_t *fout, uint32_t *factor_n, uint32_t *factor_k, uint32_t *factor_m, uint32_t *factor_p) { uint64_t cur, best; uint32_t n, k, m, p; best = 0; *factor_n = 0; *factor_k = 0; *factor_m = 0; *factor_p = 0; for (n = aw_clk_factor_get_min(&sc->n); n <= aw_clk_factor_get_max(&sc->n); ) { for (k = aw_clk_factor_get_min(&sc->k); k <= aw_clk_factor_get_max(&sc->k); ) { for (m = aw_clk_factor_get_min(&sc->m); m <= aw_clk_factor_get_max(&sc->m); ) { for (p = aw_clk_factor_get_min(&sc->p); p <= aw_clk_factor_get_max(&sc->p); ) { cur = (fparent * n * k) / (m * p); if ((*fout - cur) < (*fout - best)) { best = cur; *factor_n = n; *factor_k = k; *factor_m = m; *factor_p = p; } if (best == *fout) return (best); if ((sc->p.flags & AW_CLK_FACTOR_POWER_OF_TWO) != 0) p <<= 1; else p++; } if ((sc->m.flags & AW_CLK_FACTOR_POWER_OF_TWO) != 0) m <<= 1; else m++; } if ((sc->k.flags & AW_CLK_FACTOR_POWER_OF_TWO) != 0) k <<= 1; else k++; } if ((sc->n.flags & AW_CLK_FACTOR_POWER_OF_TWO) != 0) n <<= 1; else n++; } return best; } static void aw_clk_nkmp_set_freq_scale(struct clknode *clk, struct aw_clk_nkmp_sc *sc, uint32_t factor_n, uint32_t factor_k, uint32_t factor_m, uint32_t factor_p) { uint32_t val, n, k, m, p; int retry; DEVICE_LOCK(clk); READ4(clk, sc->offset, &val); n = aw_clk_get_factor(val, &sc->n); k = aw_clk_get_factor(val, &sc->k); m = aw_clk_get_factor(val, &sc->m); p = aw_clk_get_factor(val, &sc->p); if (p < factor_p) { val &= ~sc->p.mask; val |= aw_clk_factor_get_value(&sc->p, factor_p) << sc->p.shift; WRITE4(clk, sc->offset, val); DELAY(2000); } if (m < factor_m) { val &= ~sc->m.mask; val |= aw_clk_factor_get_value(&sc->m, factor_m) << sc->m.shift; WRITE4(clk, sc->offset, val); DELAY(2000); } val &= ~sc->n.mask; val &= ~sc->k.mask; val |= aw_clk_factor_get_value(&sc->n, factor_n) << sc->n.shift; val |= aw_clk_factor_get_value(&sc->k, factor_k) << sc->k.shift; WRITE4(clk, sc->offset, val); DELAY(2000); if (m > factor_m) { val &= ~sc->m.mask; val |= aw_clk_factor_get_value(&sc->m, factor_m) << sc->m.shift; WRITE4(clk, sc->offset, val); DELAY(2000); } if (p > factor_p) { val &= ~sc->p.mask; val |= aw_clk_factor_get_value(&sc->p, factor_p) << sc->p.shift; WRITE4(clk, sc->offset, val); DELAY(2000); } if ((sc->flags & AW_CLK_HAS_LOCK) != 0) { for (retry = 0; retry < sc->lock_retries; retry++) { READ4(clk, sc->offset, &val); if ((val & (1 << sc->lock_shift)) != 0) break; DELAY(1000); } } DEVICE_UNLOCK(clk); } static int aw_clk_nkmp_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout, int flags, int *stop) { struct aw_clk_nkmp_sc *sc; uint64_t best; uint32_t val, best_n, best_k, best_m, best_p; int retry; sc = clknode_get_softc(clk); best = aw_clk_nkmp_find_best(sc, fparent, fout, &best_n, &best_k, &best_m, &best_p); if ((flags & CLK_SET_DRYRUN) != 0) { *fout = best; *stop = 1; return (0); } if ((best < *fout) && ((flags & CLK_SET_ROUND_DOWN) != 0)) { *stop = 1; return (ERANGE); } if ((best > *fout) && ((flags & CLK_SET_ROUND_UP) != 0)) { *stop = 1; return (ERANGE); } if ((sc->flags & AW_CLK_SCALE_CHANGE) != 0) aw_clk_nkmp_set_freq_scale(clk, sc, best_n, best_k, best_m, best_p); else { DEVICE_LOCK(clk); READ4(clk, sc->offset, &val); val &= ~sc->n.mask; val &= ~sc->k.mask; val &= ~sc->m.mask; val &= ~sc->p.mask; val |= aw_clk_factor_get_value(&sc->n, best_n) << sc->n.shift; val |= aw_clk_factor_get_value(&sc->k, best_k) << sc->k.shift; val |= aw_clk_factor_get_value(&sc->m, best_m) << sc->m.shift; val |= aw_clk_factor_get_value(&sc->p, best_p) << sc->p.shift; WRITE4(clk, sc->offset, val); DELAY(2000); DEVICE_UNLOCK(clk); if ((sc->flags & AW_CLK_HAS_UPDATE) != 0) { DEVICE_LOCK(clk); READ4(clk, sc->offset, &val); val |= 1 << sc->update_shift; WRITE4(clk, sc->offset, val); DELAY(2000); DEVICE_UNLOCK(clk); } if ((sc->flags & AW_CLK_HAS_LOCK) != 0) { for (retry = 0; retry < sc->lock_retries; retry++) { READ4(clk, sc->offset, &val); if ((val & (1 << sc->lock_shift)) != 0) break; DELAY(1000); } } } *fout = best; *stop = 1; return (0); } static int aw_clk_nkmp_recalc(struct clknode *clk, uint64_t *freq) { struct aw_clk_nkmp_sc *sc; uint32_t val, m, n, k, p; sc = clknode_get_softc(clk); DEVICE_LOCK(clk); READ4(clk, sc->offset, &val); DEVICE_UNLOCK(clk); n = aw_clk_get_factor(val, &sc->n); k = aw_clk_get_factor(val, &sc->k); m = aw_clk_get_factor(val, &sc->m); p = aw_clk_get_factor(val, &sc->p); *freq = (*freq * n * k) / (m * p); return (0); } static clknode_method_t aw_nkmp_clknode_methods[] = { /* Device interface */ CLKNODEMETHOD(clknode_init, aw_clk_nkmp_init), CLKNODEMETHOD(clknode_set_gate, aw_clk_nkmp_set_gate), CLKNODEMETHOD(clknode_set_mux, aw_clk_nkmp_set_mux), CLKNODEMETHOD(clknode_recalc_freq, aw_clk_nkmp_recalc), CLKNODEMETHOD(clknode_set_freq, aw_clk_nkmp_set_freq), CLKNODEMETHOD_END }; DEFINE_CLASS_1(aw_nkmp_clknode, aw_nkmp_clknode_class, aw_nkmp_clknode_methods, sizeof(struct aw_clk_nkmp_sc), clknode_class); int aw_clk_nkmp_register(struct clkdom *clkdom, struct aw_clk_nkmp_def *clkdef) { struct clknode *clk; struct aw_clk_nkmp_sc *sc; clk = clknode_create(clkdom, &aw_nkmp_clknode_class, &clkdef->clkdef); if (clk == NULL) return (1); sc = clknode_get_softc(clk); sc->offset = clkdef->offset; sc->n.shift = clkdef->n.shift; sc->n.width = clkdef->n.width; sc->n.mask = ((1 << clkdef->n.width) - 1) << sc->n.shift; sc->n.value = clkdef->n.value; sc->n.flags = clkdef->n.flags; sc->k.shift = clkdef->k.shift; sc->k.width = clkdef->k.width; sc->k.mask = ((1 << clkdef->k.width) - 1) << sc->k.shift; sc->k.value = clkdef->k.value; sc->k.flags = clkdef->k.flags; sc->m.shift = clkdef->m.shift; sc->m.width = clkdef->m.width; sc->m.mask = ((1 << clkdef->m.width) - 1) << sc->m.shift; sc->m.value = clkdef->m.value; sc->m.flags = clkdef->m.flags; sc->p.shift = clkdef->p.shift; sc->p.width = clkdef->p.width; sc->p.mask = ((1 << clkdef->p.width) - 1) << sc->p.shift; sc->p.value = clkdef->p.value; sc->p.flags = clkdef->p.flags; sc->mux_shift = clkdef->mux_shift; sc->mux_mask = ((1 << clkdef->mux_width) - 1) << sc->mux_shift; sc->gate_shift = clkdef->gate_shift; sc->lock_shift = clkdef->lock_shift; sc->lock_retries = clkdef->lock_retries; sc->update_shift = clkdef->update_shift; sc->flags = clkdef->flags; clknode_register(clkdom, clk); return (0); } Index: head/sys/arm/allwinner/clkng/aw_clk_nm.c =================================================================== --- head/sys/arm/allwinner/clkng/aw_clk_nm.c (revision 355356) +++ head/sys/arm/allwinner/clkng/aw_clk_nm.c (revision 355357) @@ -1,352 +1,351 @@ /*- * Copyright (c) 2017 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include "clkdev_if.h" /* * clknode for clocks matching the formula : * * clk = clkin / n / m * */ struct aw_clk_nm_sc { uint32_t offset; struct aw_clk_factor m; struct aw_clk_factor n; struct aw_clk_factor prediv; uint32_t mux_shift; uint32_t mux_mask; uint32_t gate_shift; uint32_t lock_shift; uint32_t lock_retries; uint32_t flags; }; #define WRITE4(_clk, off, val) \ CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) #define READ4(_clk, off, val) \ CLKDEV_READ_4(clknode_get_device(_clk), off, val) #define DEVICE_LOCK(_clk) \ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) #define DEVICE_UNLOCK(_clk) \ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) static int aw_clk_nm_init(struct clknode *clk, device_t dev) { struct aw_clk_nm_sc *sc; uint32_t val, idx; sc = clknode_get_softc(clk); idx = 0; if ((sc->flags & AW_CLK_HAS_MUX) != 0) { DEVICE_LOCK(clk); READ4(clk, sc->offset, &val); DEVICE_UNLOCK(clk); idx = (val & sc->mux_mask) >> sc->mux_shift; } clknode_init_parent_idx(clk, idx); return (0); } static int aw_clk_nm_set_gate(struct clknode *clk, bool enable) { struct aw_clk_nm_sc *sc; uint32_t val; sc = clknode_get_softc(clk); if ((sc->flags & AW_CLK_HAS_GATE) == 0) return (0); DEVICE_LOCK(clk); READ4(clk, sc->offset, &val); if (enable) val |= (1 << sc->gate_shift); else val &= ~(1 << sc->gate_shift); WRITE4(clk, sc->offset, val); DEVICE_UNLOCK(clk); return (0); } static int aw_clk_nm_set_mux(struct clknode *clk, int index) { struct aw_clk_nm_sc *sc; uint32_t val; sc = clknode_get_softc(clk); if ((sc->flags & AW_CLK_HAS_MUX) == 0) return (0); DEVICE_LOCK(clk); READ4(clk, sc->offset, &val); val &= ~sc->mux_mask; val |= index << sc->mux_shift; WRITE4(clk, sc->offset, val); DEVICE_UNLOCK(clk); return (0); } static uint64_t aw_clk_nm_find_best(struct aw_clk_nm_sc *sc, uint64_t fparent, uint64_t *fout, uint32_t *factor_n, uint32_t *factor_m) { uint64_t cur, best; uint32_t m, n, max_m, max_n, min_m, min_n; *factor_n = *factor_m = 0; max_m = aw_clk_factor_get_max(&sc->m); max_n = aw_clk_factor_get_max(&sc->n); min_m = aw_clk_factor_get_min(&sc->m); min_n = aw_clk_factor_get_min(&sc->n); for (m = min_m; m <= max_m; ) { for (n = min_m; n <= max_n; ) { cur = fparent / n / m; if (abs(*fout - cur) < abs(*fout - best)) { best = cur; *factor_n = n; *factor_m = m; } if ((sc->n.flags & AW_CLK_FACTOR_POWER_OF_TWO) != 0) n <<= 1; else n++; } if ((sc->m.flags & AW_CLK_FACTOR_POWER_OF_TWO) != 0) m <<= 1; else m++; } return (best); } static int aw_clk_nm_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout, int flags, int *stop) { struct aw_clk_nm_sc *sc; struct clknode *p_clk; const char **p_names; uint64_t cur, best; uint32_t val, m, n, best_m, best_n; int p_idx, best_parent, retry; sc = clknode_get_softc(clk); best = cur = 0; best_parent = 0; if ((sc->flags & AW_CLK_REPARENT) != 0) { p_names = clknode_get_parent_names(clk); for (p_idx = 0; p_idx != clknode_get_parents_num(clk); p_idx++) { p_clk = clknode_find_by_name(p_names[p_idx]); clknode_get_freq(p_clk, &fparent); cur = aw_clk_nm_find_best(sc, fparent, fout, &n, &m); if ((*fout - cur) < (*fout - best)) { best = cur; best_parent = p_idx; best_n = n; best_m = m; } } p_idx = clknode_get_parent_idx(clk); p_clk = clknode_get_parent(clk); clknode_get_freq(p_clk, &fparent); } else { best = aw_clk_nm_find_best(sc, fparent, fout, &best_n, &best_m); } if ((flags & CLK_SET_DRYRUN) != 0) { *fout = best; *stop = 1; return (0); } if ((best < *fout) && ((flags & CLK_SET_ROUND_DOWN) == 0)) { *stop = 1; return (ERANGE); } if ((best > *fout) && ((flags & CLK_SET_ROUND_UP) == 0)) { *stop = 1; return (ERANGE); } if ((sc->flags & AW_CLK_REPARENT) != 0 && p_idx != best_parent) clknode_set_parent_by_idx(clk, best_parent); DEVICE_LOCK(clk); READ4(clk, sc->offset, &val); n = aw_clk_factor_get_value(&sc->n, best_n); m = aw_clk_factor_get_value(&sc->m, best_m); val &= ~sc->n.mask; val &= ~sc->m.mask; val |= n << sc->n.shift; val |= m << sc->m.shift; WRITE4(clk, sc->offset, val); DEVICE_UNLOCK(clk); if ((sc->flags & AW_CLK_HAS_LOCK) != 0) { for (retry = 0; retry < sc->lock_retries; retry++) { READ4(clk, sc->offset, &val); if ((val & (1 << sc->lock_shift)) != 0) break; DELAY(1000); } } *fout = best; *stop = 1; return (0); } static int aw_clk_nm_recalc(struct clknode *clk, uint64_t *freq) { struct aw_clk_nm_sc *sc; uint32_t val, m, n, prediv; sc = clknode_get_softc(clk); DEVICE_LOCK(clk); READ4(clk, sc->offset, &val); DEVICE_UNLOCK(clk); m = aw_clk_get_factor(val, &sc->m); n = aw_clk_get_factor(val, &sc->n); if (sc->flags & AW_CLK_HAS_PREDIV) prediv = aw_clk_get_factor(val, &sc->prediv); else prediv = 1; *freq = *freq / prediv / n / m; return (0); } static clknode_method_t aw_nm_clknode_methods[] = { /* Device interface */ CLKNODEMETHOD(clknode_init, aw_clk_nm_init), CLKNODEMETHOD(clknode_set_gate, aw_clk_nm_set_gate), CLKNODEMETHOD(clknode_set_mux, aw_clk_nm_set_mux), CLKNODEMETHOD(clknode_recalc_freq, aw_clk_nm_recalc), CLKNODEMETHOD(clknode_set_freq, aw_clk_nm_set_freq), CLKNODEMETHOD_END }; DEFINE_CLASS_1(aw_nm_clknode, aw_nm_clknode_class, aw_nm_clknode_methods, sizeof(struct aw_clk_nm_sc), clknode_class); int aw_clk_nm_register(struct clkdom *clkdom, struct aw_clk_nm_def *clkdef) { struct clknode *clk; struct aw_clk_nm_sc *sc; clk = clknode_create(clkdom, &aw_nm_clknode_class, &clkdef->clkdef); if (clk == NULL) return (1); sc = clknode_get_softc(clk); sc->offset = clkdef->offset; sc->m.shift = clkdef->m.shift; sc->m.width = clkdef->m.width; sc->m.mask = ((1 << sc->m.width) - 1) << sc->m.shift; sc->m.value = clkdef->m.value; sc->m.flags = clkdef->m.flags; sc->n.shift = clkdef->n.shift; sc->n.width = clkdef->n.width; sc->n.mask = ((1 << sc->n.width) - 1) << sc->n.shift; sc->n.value = clkdef->n.value; sc->n.flags = clkdef->n.flags; sc->prediv.shift = clkdef->prediv.shift; sc->prediv.width = clkdef->prediv.width; sc->prediv.mask = ((1 << sc->prediv.width) - 1) << sc->prediv.shift; sc->prediv.value = clkdef->prediv.value; sc->prediv.flags = clkdef->prediv.flags; sc->prediv.cond_shift = clkdef->prediv.cond_shift; if (clkdef->prediv.cond_width != 0) sc->prediv.cond_mask = ((1 << clkdef->prediv.cond_width) - 1) << sc->prediv.shift; else sc->prediv.cond_mask = clkdef->prediv.cond_mask; sc->prediv.cond_value = clkdef->prediv.cond_value; sc->mux_shift = clkdef->mux_shift; sc->mux_mask = ((1 << clkdef->mux_width) - 1) << sc->mux_shift; sc->gate_shift = clkdef->gate_shift; sc->lock_shift = clkdef->lock_shift; sc->lock_retries = clkdef->lock_retries; sc->flags = clkdef->flags; clknode_register(clkdom, clk); return (0); } Index: head/sys/arm/allwinner/clkng/aw_clk_nm.h =================================================================== --- head/sys/arm/allwinner/clkng/aw_clk_nm.h (revision 355356) +++ head/sys/arm/allwinner/clkng/aw_clk_nm.h (revision 355357) @@ -1,53 +1,52 @@ /*- * Copyright (c) 2017 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef __AW_CLK_NM_H__ #define __AW_CLK_NM_H__ #include struct aw_clk_nm_def { struct clknode_init_def clkdef; uint32_t offset; struct aw_clk_factor m; struct aw_clk_factor n; struct aw_clk_factor prediv; uint32_t mux_shift; uint32_t mux_width; uint32_t gate_shift; uint32_t lock_shift; uint32_t lock_retries; uint32_t flags; }; int aw_clk_nm_register(struct clkdom *clkdom, struct aw_clk_nm_def *clkdef); #endif /* __AW_CLK_NM_H__ */ Index: head/sys/arm/allwinner/clkng/aw_clk_prediv_mux.c =================================================================== --- head/sys/arm/allwinner/clkng/aw_clk_prediv_mux.c (revision 355356) +++ head/sys/arm/allwinner/clkng/aw_clk_prediv_mux.c (revision 355357) @@ -1,184 +1,183 @@ /*- * Copyright (c) 2017 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include "clkdev_if.h" /* * clknode for clocks matching the formula : * * clk = clkin / prediv / div * * and where prediv is conditional * */ struct aw_clk_prediv_mux_sc { uint32_t offset; uint32_t mux_shift; uint32_t mux_mask; struct aw_clk_factor div; struct aw_clk_factor prediv; uint32_t flags; }; #define WRITE4(_clk, off, val) \ CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) #define READ4(_clk, off, val) \ CLKDEV_READ_4(clknode_get_device(_clk), off, val) #define MODIFY4(_clk, off, clr, set ) \ CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set) #define DEVICE_LOCK(_clk) \ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) #define DEVICE_UNLOCK(_clk) \ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) static int aw_clk_prediv_mux_init(struct clknode *clk, device_t dev) { struct aw_clk_prediv_mux_sc *sc; uint32_t val; sc = clknode_get_softc(clk); DEVICE_LOCK(clk); READ4(clk, sc->offset, &val); DEVICE_UNLOCK(clk); /* Init the current parent */ val = (val & sc->mux_mask) >> sc->mux_shift; clknode_init_parent_idx(clk, val); return (0); } static int aw_clk_prediv_mux_set_mux(struct clknode *clk, int index) { struct aw_clk_prediv_mux_sc *sc; uint32_t val; sc = clknode_get_softc(clk); DEVICE_LOCK(clk); READ4(clk, sc->offset, &val); val &= ~sc->mux_mask; val |= index << sc->mux_shift; WRITE4(clk, sc->offset, val); DEVICE_UNLOCK(clk); return (0); } static int aw_clk_prediv_mux_recalc(struct clknode *clk, uint64_t *freq) { struct aw_clk_prediv_mux_sc *sc; uint32_t val, div, prediv; sc = clknode_get_softc(clk); DEVICE_LOCK(clk); READ4(clk, sc->offset, &val); DEVICE_UNLOCK(clk); div = aw_clk_get_factor(val, &sc->div); prediv = aw_clk_get_factor(val, &sc->prediv); *freq = *freq / prediv / div; return (0); } static clknode_method_t aw_prediv_mux_clknode_methods[] = { /* Device interface */ CLKNODEMETHOD(clknode_init, aw_clk_prediv_mux_init), CLKNODEMETHOD(clknode_set_mux, aw_clk_prediv_mux_set_mux), CLKNODEMETHOD(clknode_recalc_freq, aw_clk_prediv_mux_recalc), CLKNODEMETHOD_END }; DEFINE_CLASS_1(aw_prediv_mux_clknode, aw_prediv_mux_clknode_class, aw_prediv_mux_clknode_methods, sizeof(struct aw_clk_prediv_mux_sc), clknode_class); int aw_clk_prediv_mux_register(struct clkdom *clkdom, struct aw_clk_prediv_mux_def *clkdef) { struct clknode *clk; struct aw_clk_prediv_mux_sc *sc; clk = clknode_create(clkdom, &aw_prediv_mux_clknode_class, &clkdef->clkdef); if (clk == NULL) return (1); sc = clknode_get_softc(clk); sc->offset = clkdef->offset; sc->mux_shift = clkdef->mux_shift; sc->mux_mask = ((1 << clkdef->mux_width) - 1) << sc->mux_shift; sc->div.shift = clkdef->div.shift; sc->div.mask = ((1 << clkdef->div.width) - 1) << sc->div.shift; sc->div.value = clkdef->div.value; sc->div.cond_shift = clkdef->div.cond_shift; sc->div.cond_mask = ((1 << clkdef->div.cond_width) - 1) << sc->div.shift; sc->div.cond_value = clkdef->div.cond_value; sc->div.flags = clkdef->div.flags; sc->prediv.shift = clkdef->prediv.shift; sc->prediv.mask = ((1 << clkdef->prediv.width) - 1) << sc->prediv.shift; sc->prediv.value = clkdef->prediv.value; sc->prediv.cond_shift = clkdef->prediv.cond_shift; if (clkdef->prediv.cond_width != 0) sc->prediv.cond_mask = ((1 << clkdef->prediv.cond_width) - 1) << sc->prediv.shift; else sc->prediv.cond_mask = clkdef->prediv.cond_mask; sc->prediv.cond_value = clkdef->prediv.cond_value; sc->prediv.flags = clkdef->prediv.flags; sc->flags = clkdef->flags; clknode_register(clkdom, clk); return (0); } Index: head/sys/arm/allwinner/clkng/aw_clk_prediv_mux.h =================================================================== --- head/sys/arm/allwinner/clkng/aw_clk_prediv_mux.h (revision 355356) +++ head/sys/arm/allwinner/clkng/aw_clk_prediv_mux.h (revision 355357) @@ -1,49 +1,48 @@ /*- * Copyright (c) 2017 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef __AW_CLK_PREDIV_MUX_H__ #define __AW_CLK_PREDIV_MUX_H__ #include struct aw_clk_prediv_mux_def { struct clknode_init_def clkdef; uint32_t offset; uint32_t mux_shift; uint32_t mux_width; struct aw_clk_factor div; struct aw_clk_factor prediv; uint32_t flags; }; int aw_clk_prediv_mux_register(struct clkdom *clkdom, struct aw_clk_prediv_mux_def *clkdef); #endif /* __AW_CLK_PREDIV_MUX_H__ */ Index: head/sys/arm/allwinner/h3/h3_padconf.c =================================================================== --- head/sys/arm/allwinner/h3/h3_padconf.c (revision 355356) +++ head/sys/arm/allwinner/h3/h3_padconf.c (revision 355357) @@ -1,151 +1,150 @@ /*- * Copyright (c) 2016-2017 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #if defined(__aarch64__) #include "opt_soc.h" #endif #include #if defined(SOC_ALLWINNER_H3) || defined(SOC_ALLWINNER_H5) const static struct allwinner_pins h3_pins[] = { {"PA0", 0, 0, {"gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "pa_eint0", NULL}, 6, 0}, {"PA1", 0, 1, {"gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "pa_eint1", NULL}, 6, 1}, {"PA2", 0, 2, {"gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "pa_eint2", NULL}, 6, 2}, {"PA3", 0, 3, {"gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "pa_eint3", NULL}, 6, 3}, {"PA4", 0, 4, {"gpio_in", "gpio_out", "uart0", NULL, NULL, NULL, "pa_eint4", NULL}, 6, 4}, {"PA5", 0, 5, {"gpio_in", "gpio_out", "uart0", "pwm0", NULL, NULL, "pa_eint5", NULL}, 6, 5}, {"PA6", 0, 6, {"gpio_in", "gpio_out", "sim", NULL, NULL, NULL, "pa_eint6", NULL}, 6, 6}, {"PA7", 0, 7, {"gpio_in", "gpio_out", "sim", NULL, NULL, NULL, "pa_eint7", NULL}, 6, 7}, {"PA8", 0, 8, {"gpio_in", "gpio_out", "sim", NULL, NULL, NULL, "pa_eint8", NULL}, 6, 8}, {"PA9", 0, 9, {"gpio_in", "gpio_out", "sim", NULL, NULL, NULL, "pa_eint9", NULL}, 6, 9}, {"PA10", 0, 10, {"gpio_in", "gpio_out", "sim", NULL, NULL, NULL, "pa_eint10", NULL}, 6, 10}, {"PA11", 0, 11, {"gpio_in", "gpio_out", "i2c0", "di", NULL, NULL, "pa_eint11", NULL}, 6, 11}, {"PA12", 0, 12, {"gpio_in", "gpio_out", "i2c0", "di", NULL, NULL, "pa_eint12", NULL}, 6, 12}, {"PA13", 0, 13, {"gpio_in", "gpio_out", "spi1", "uart3", NULL, NULL, "pa_eint13", NULL}, 6, 13}, {"PA14", 0, 14, {"gpio_in", "gpio_out", "spi1", "uart3", NULL, NULL, "pa_eint14", NULL}, 6, 14}, {"PA15", 0, 15, {"gpio_in", "gpio_out", "spi1", "uart3", NULL, NULL, "pa_eint15", NULL}, 6, 15}, {"PA16", 0, 16, {"gpio_in", "gpio_out", "spi1", "uart3", NULL, NULL, "pa_eint16", NULL}, 6, 16}, {"PA17", 0, 17, {"gpio_in", "gpio_out", "spdif", NULL, NULL, NULL, "pa_eint17", NULL}, 6, 17}, {"PA18", 0, 18, {"gpio_in", "gpio_out", "i2s0", "i2c1", NULL, NULL, "pa_eint18", NULL}, 6, 18}, {"PA19", 0, 19, {"gpio_in", "gpio_out", "i2s0", "i2c1", NULL, NULL, "pa_eint19", NULL}, 6, 19}, {"PA20", 0, 20, {"gpio_in", "gpio_out", "i2s0", "sim", NULL, NULL, "pa_eint20", NULL}, 6, 20}, {"PA21", 0, 21, {"gpio_in", "gpio_out", "i2s0", "sim", NULL, NULL, "pa_eint21", NULL}, 6, 21}, {"PC0", 2, 0, {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}}, {"PC1", 2, 1, {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}}, {"PC2", 2, 2, {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}}, {"PC3", 2, 3, {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}}, {"PC4", 2, 4, {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}}, {"PC5", 2, 5, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC6", 2, 6, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC7", 2, 7, {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}}, {"PC8", 2, 8, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC9", 2, 9, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC10", 2, 10, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC11", 2, 11, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC12", 2, 12, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC13", 2, 13, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC14", 2, 14, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC15", 2, 15, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PC16", 2, 16, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, {"PD0", 3, 0, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, {"PD1", 3, 1, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, {"PD2", 3, 2, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, {"PD3", 3, 3, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, {"PD4", 3, 4, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, {"PD5", 3, 5, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, {"PD6", 3, 6, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, {"PD7", 3, 7, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, {"PD8", 3, 8, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, {"PD9", 3, 9, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, {"PD10", 3, 10, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, {"PD11", 3, 11, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, {"PD12", 3, 12, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, {"PD13", 3, 13, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, {"PD14", 3, 14, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, {"PD15", 3, 15, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, {"PD16", 3, 16, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, {"PD17", 3, 17, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, {"PE0", 4, 0, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, {"PE1", 4, 1, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, {"PE2", 4, 2, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, {"PE3", 4, 3, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, {"PE4", 4, 4, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, {"PE5", 4, 5, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, {"PE6", 4, 6, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, {"PE7", 4, 7, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, {"PE8", 4, 8, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, {"PE9", 4, 9, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, {"PE10", 4, 10, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, {"PE11", 4, 11, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, {"PE12", 4, 12, {"gpio_in", "gpio_out", "csi", "i2c2", NULL, NULL, NULL, NULL}}, {"PE13", 4, 13, {"gpio_in", "gpio_out", "csi", "i2c2", NULL, NULL, NULL, NULL}}, {"PE14", 4, 14, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, {"PE15", 4, 15, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, {"PF0", 5, 0, {"gpio_in", "gpio_out", "mmc0", "jtag", NULL, NULL, NULL, NULL}}, {"PF1", 5, 1, {"gpio_in", "gpio_out", "mmc0", "jtag", NULL, NULL, NULL, NULL}}, {"PF2", 5, 2, {"gpio_in", "gpio_out", "mmc0", "uart0", NULL, NULL, NULL, NULL}}, {"PF3", 5, 3, {"gpio_in", "gpio_out", "mmc0", "jtag", NULL, NULL, NULL, NULL}}, {"PF4", 5, 4, {"gpio_in", "gpio_out", "mmc0", "uart0", NULL, NULL, NULL, NULL}}, {"PF5", 5, 5, {"gpio_in", "gpio_out", "mmc0", "jtag", NULL, NULL, NULL, NULL}}, {"PF6", 5, 6, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, {"PG0", 6, 0, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint0", NULL}, 6, 0}, {"PG1", 6, 1, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint1", NULL}, 6, 1}, {"PG2", 6, 2, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint2", NULL}, 6, 2}, {"PG3", 6, 3, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint3", NULL}, 6, 3}, {"PG4", 6, 4, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint4", NULL}, 6, 4}, {"PG5", 6, 5, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint5", NULL}, 6, 5}, {"PG6", 6, 6, {"gpio_in", "gpio_out", "uart1", NULL, NULL, NULL, "pg_eint6", NULL}, 6, 6}, {"PG7", 6, 7, {"gpio_in", "gpio_out", "uart1", NULL, NULL, NULL, "pg_eint7", NULL}, 6, 7}, {"PG8", 6, 8, {"gpio_in", "gpio_out", "uart1", NULL, NULL, NULL, "pg_eint8", NULL}, 6, 8}, {"PG9", 6, 9, {"gpio_in", "gpio_out", "uart1", NULL, NULL, NULL, "pg_eint9", NULL}, 6, 9}, {"PG10", 6, 10, {"gpio_in", "gpio_out", "i2s1", NULL, NULL, NULL, "pg_eint10", NULL}, 6, 10}, {"PG11", 6, 11, {"gpio_in", "gpio_out", "i2s1", NULL, NULL, NULL, "pg_eint11", NULL}, 6, 11}, {"PG12", 6, 12, {"gpio_in", "gpio_out", "i2s1", NULL, NULL, NULL, "pg_eint12", NULL}, 6, 12}, {"PG13", 6, 13, {"gpio_in", "gpio_out", "i2s1", NULL, NULL, NULL, "pg_eint13", NULL}, 6, 13}, }; const struct allwinner_padconf h3_padconf = { .npins = nitems(h3_pins), .pins = h3_pins, }; #endif /* SOC_ALLWINNER_H3 */ Index: head/sys/arm/allwinner/h3/h3_r_padconf.c =================================================================== --- head/sys/arm/allwinner/h3/h3_r_padconf.c (revision 355356) +++ head/sys/arm/allwinner/h3/h3_r_padconf.c (revision 355357) @@ -1,64 +1,63 @@ /*- * Copyright (c) 2016-2017 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #if defined(__aarch64__) #include "opt_soc.h" #endif #include #if defined(SOC_ALLWINNER_H3) || defined(SOC_ALLWINNER_H5) const static struct allwinner_pins h3_r_pins[] = { {"PL0", 0, 0, {"gpio_in", "gpio_out", "s_twi", NULL, NULL, NULL, "pl_eint0", NULL}, 6, 0}, {"PL1", 0, 1, {"gpio_in", "gpio_out", "s_twi", NULL, NULL, NULL, "pl_eint1", NULL}, 6, 1}, {"PL2", 0, 2, {"gpio_in", "gpio_out", "s_uart", NULL, NULL, NULL, "pl_eint2", NULL}, 6, 2}, {"PL3", 0, 3, {"gpio_in", "gpio_out", "s_uart", NULL, NULL, NULL, "pl_eint3", NULL}, 6, 3}, {"PL4", 0, 4, {"gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, "pl_eint4", NULL}, 6, 4}, {"PL5", 0, 5, {"gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, "pl_eint5", NULL}, 6, 5}, {"PL6", 0, 6, {"gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, "pl_eint6", NULL}, 6, 6}, {"PL7", 0, 7, {"gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, "pl_eint7", NULL}, 6, 7}, {"PL8", 0, 8, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, "pl_eint8", NULL}, 6, 8}, {"PL9", 0, 9, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, "pl_eint9", NULL}, 6, 9}, {"PL10", 0, 10, {"gpio_in", "gpio_out", "s_pwm", NULL, NULL, NULL, "pl_eint10", NULL}, 6, 10}, {"PL11", 0, 11, {"gpio_in", "gpio_out", "s_cir_rx", NULL, NULL, NULL, "pl_eint11", NULL}, 6, 11}, }; const struct allwinner_padconf h3_r_padconf = { .npins = nitems(h3_r_pins), .pins = h3_r_pins, }; #endif /* SOC_ALLWINNER_H3 */ Index: head/sys/arm/broadcom/bcm2835/bcm2836_mp.h =================================================================== --- head/sys/arm/broadcom/bcm2835/bcm2836_mp.h (revision 355356) +++ head/sys/arm/broadcom/bcm2835/bcm2836_mp.h (revision 355357) @@ -1,38 +1,37 @@ /*- * Copyright (C) 2016 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _BCM2836_MP_H_ #define _BCM2836_MP_H_ void bcm2836_mp_setmaxid(platform_t plat); void bcm2836_mp_start_ap(platform_t plat); #endif /* _BCM2836_MP_H_ */ Index: head/sys/arm64/rockchip/clk/rk3328_cru.c =================================================================== --- head/sys/arm64/rockchip/clk/rk3328_cru.c (revision 355356) +++ head/sys/arm64/rockchip/clk/rk3328_cru.c (revision 355357) @@ -1,1129 +1,1128 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* GATES */ #define ACLK_PERI 153 #define PCLK_GPIO0 200 #define PCLK_GPIO1 201 #define PCLK_GPIO2 202 #define PCLK_GPIO3 203 #define PCLK_I2C0 205 #define PCLK_I2C1 206 #define PCLK_I2C2 207 #define PCLK_I2C3 208 #define PCLK_TSADC 213 #define HCLK_SDMMC 317 #define HCLK_SDIO 318 #define HCLK_EMMC 319 #define HCLK_SDMMC_EXT 320 static struct rk_cru_gate rk3328_gates[] = { /* CRU_CLKGATE_CON0 */ CRU_GATE(0, "apll_core", "apll", 0x200, 0) CRU_GATE(0, "dpll_core", "dpll", 0x200, 1) CRU_GATE(0, "gpll_core", "gpll", 0x200, 2) CRU_GATE(0, "npll_core", "npll", 0x200, 12) /* CRU_CLKGATE_CON4 */ CRU_GATE(0, "gpll_peri", "gpll", 0x210, 0) CRU_GATE(0, "cpll_peri", "cpll", 0x210, 1) /* CRU_CLKGATE_CON8 */ CRU_GATE(0, "pclk_bus", "pclk_bus_pre", 0x220, 3) CRU_GATE(0, "pclk_phy_pre", "pclk_bus_pre", 0x220, 4) /* CRU_CLKGATE_CON10 */ CRU_GATE(ACLK_PERI, "aclk_peri", "aclk_peri_pre", 0x228, 0) /* CRU_CLKGATE_CON15*/ CRU_GATE(PCLK_I2C0, "pclk_i2c0", "pclk_bus", 0x23C, 10) /* CRU_CLKGATE_CON16 */ CRU_GATE(PCLK_I2C1, "pclk_i2c1", "pclk_bus", 0x23C, 0) CRU_GATE(PCLK_I2C2, "pclk_i2c2", "pclk_bus", 0x23C, 1) CRU_GATE(PCLK_I2C3, "pclk_i2c3", "pclk_bus", 0x23C, 2) CRU_GATE(PCLK_TSADC, "pclk_tsadc", "pclk_bus", 0x23C, 14) CRU_GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_bus", 0x240, 7) CRU_GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_bus", 0x240, 8) CRU_GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_bus", 0x240, 9) CRU_GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_bus", 0x240, 10) /* CRU_CLKGATE_CON19 */ CRU_GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0x24C, 0) CRU_GATE(HCLK_SDIO, "hclk_sdio", "hclk_peri", 0x24C, 1) CRU_GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0x24C, 2) CRU_GATE(HCLK_SDMMC_EXT, "hclk_sdmmc_ext", "hclk_peri", 0x24C, 15) }; /* * PLLs */ #define PLL_APLL 1 #define PLL_DPLL 2 #define PLL_CPLL 3 #define PLL_GPLL 4 #define PLL_NPLL 5 static struct rk_clk_pll_rate rk3328_pll_rates[] = { { .freq = 1608000000, .refdiv = 1, .fbdiv = 67, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1584000000, .refdiv = 1, .fbdiv = 66, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1560000000, .refdiv = 1, .fbdiv = 65, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1536000000, .refdiv = 1, .fbdiv = 64, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1512000000, .refdiv = 1, .fbdiv = 63, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1488000000, .refdiv = 1, .fbdiv = 62, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1464000000, .refdiv = 1, .fbdiv = 61, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1440000000, .refdiv = 1, .fbdiv = 60, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1416000000, .refdiv = 1, .fbdiv = 59, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1392000000, .refdiv = 1, .fbdiv = 58, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1368000000, .refdiv = 1, .fbdiv = 57, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1344000000, .refdiv = 1, .fbdiv = 56, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1320000000, .refdiv = 1, .fbdiv = 55, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1296000000, .refdiv = 1, .fbdiv = 54, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1272000000, .refdiv = 1, .fbdiv = 53, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1248000000, .refdiv = 1, .fbdiv = 52, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1200000000, .refdiv = 1, .fbdiv = 50, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1188000000, .refdiv = 2, .fbdiv = 99, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1104000000, .refdiv = 1, .fbdiv = 46, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1100000000, .refdiv = 12, .fbdiv = 550, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1008000000, .refdiv = 1, .fbdiv = 84, .postdiv1 = 2, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 1000000000, .refdiv = 6, .fbdiv = 500, .postdiv1 = 2, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 984000000, .refdiv = 1, .fbdiv = 82, .postdiv1 = 2, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 960000000, .refdiv = 1, .fbdiv = 80, .postdiv1 = 2, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 936000000, .refdiv = 1, .fbdiv = 78, .postdiv1 = 2, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 912000000, .refdiv = 1, .fbdiv = 76, .postdiv1 = 2, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 900000000, .refdiv = 4, .fbdiv = 300, .postdiv1 = 2, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 888000000, .refdiv = 1, .fbdiv = 74, .postdiv1 = 2, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 864000000, .refdiv = 1, .fbdiv = 72, .postdiv1 = 2, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 840000000, .refdiv = 1, .fbdiv = 70, .postdiv1 = 2, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 816000000, .refdiv = 1, .fbdiv = 68, .postdiv1 = 2, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 800000000, .refdiv = 6, .fbdiv = 400, .postdiv1 = 2, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 700000000, .refdiv = 6, .fbdiv = 350, .postdiv1 = 2, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 696000000, .refdiv = 1, .fbdiv = 58, .postdiv1 = 2, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 600000000, .refdiv = 1, .fbdiv = 75, .postdiv1 = 3, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 594000000, .refdiv = 2, .fbdiv = 99, .postdiv1 = 2, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 504000000, .refdiv = 1, .fbdiv = 63, .postdiv1 = 3, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 500000000, .refdiv = 6, .fbdiv = 250, .postdiv1 = 2, .postdiv2 = 1, .dsmpd = 1, }, { .freq = 408000000, .refdiv = 1, .fbdiv = 68, .postdiv1 = 2, .postdiv2 = 2, .dsmpd = 1, }, { .freq = 312000000, .refdiv = 1, .fbdiv = 52, .postdiv1 = 2, .postdiv2 = 2, .dsmpd = 1, }, { .freq = 216000000, .refdiv = 1, .fbdiv = 72, .postdiv1 = 4, .postdiv2 = 2, .dsmpd = 1, }, { .freq = 96000000, .refdiv = 1, .fbdiv = 64, .postdiv1 = 4, .postdiv2 = 4, .dsmpd = 1, }, {}, }; static struct rk_clk_pll_rate rk3328_pll_frac_rates[] = { { .freq = 1016064000, .refdiv = 3, .fbdiv = 127, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 0, .frac = 134217, }, { .freq = 983040000, .refdiv = 24, .fbdiv = 983, .postdiv1 = 1, .postdiv2 = 1, .dsmpd = 0, .frac = 671088, }, { .freq = 491520000, .refdiv = 24, .fbdiv = 983, .postdiv1 = 2, .postdiv2 = 1, .dsmpd = 0, .frac = 671088, }, { .freq = 61440000, .refdiv = 6, .fbdiv = 215, .postdiv1 = 7, .postdiv2 = 2, .dsmpd = 0, .frac = 671088, }, { .freq = 56448000, .refdiv = 12, .fbdiv = 451, .postdiv1 = 4, .postdiv2 = 4, .dsmpd = 0, .frac = 9797894, }, { .freq = 40960000, .refdiv = 12, .fbdiv = 409, .postdiv1 = 4, .postdiv2 = 5, .dsmpd = 0, .frac = 10066329, }, {}, }; static const char *pll_parents[] = {"xin24m"}; static struct rk_clk_pll_def apll = { .clkdef = { .id = PLL_APLL, .name = "apll", .parent_names = pll_parents, .parent_cnt = nitems(pll_parents), }, .base_offset = 0x00, .gate_offset = 0x200, .gate_shift = 0, .mode_reg = 0x80, .mode_shift = 1, .flags = RK_CLK_PLL_HAVE_GATE, .frac_rates = rk3328_pll_frac_rates, }; static struct rk_clk_pll_def dpll = { .clkdef = { .id = PLL_DPLL, .name = "dpll", .parent_names = pll_parents, .parent_cnt = nitems(pll_parents), }, .base_offset = 0x20, .gate_offset = 0x200, .gate_shift = 1, .mode_reg = 0x80, .mode_shift = 4, .flags = RK_CLK_PLL_HAVE_GATE, }; static struct rk_clk_pll_def cpll = { .clkdef = { .id = PLL_CPLL, .name = "cpll", .parent_names = pll_parents, .parent_cnt = nitems(pll_parents), }, .base_offset = 0x40, .mode_reg = 0x80, .mode_shift = 8, .rates = rk3328_pll_rates, }; static struct rk_clk_pll_def gpll = { .clkdef = { .id = PLL_GPLL, .name = "gpll", .parent_names = pll_parents, .parent_cnt = nitems(pll_parents), }, .base_offset = 0x60, .gate_offset = 0x200, .gate_shift = 2, .mode_reg = 0x80, .mode_shift = 12, .flags = RK_CLK_PLL_HAVE_GATE, .frac_rates = rk3328_pll_frac_rates, }; static struct rk_clk_pll_def npll = { .clkdef = { .id = PLL_NPLL, .name = "npll", .parent_names = pll_parents, .parent_cnt = nitems(pll_parents), }, .base_offset = 0xa0, .gate_offset = 0x200, .gate_shift = 12, .mode_reg = 0x80, .mode_shift = 1, .flags = RK_CLK_PLL_HAVE_GATE, .rates = rk3328_pll_rates, }; /* CRU_CLKSEL_CON0 */ #define ACLK_BUS_PRE 136 /* Needs hdmiphy as parent too*/ static const char *aclk_bus_pre_parents[] = {"cpll", "gpll"}; static struct rk_clk_composite_def aclk_bus_pre = { .clkdef = { .id = ACLK_BUS_PRE, .name = "aclk_bus_pre", .parent_names = aclk_bus_pre_parents, .parent_cnt = nitems(aclk_bus_pre_parents), }, .muxdiv_offset = 0x100, .mux_shift = 13, .mux_width = 2, .div_shift = 8, .div_width = 5, .gate_offset = 0x220, .gate_shift = 0, .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE, }; static struct rk_clk_armclk_rates rk3328_armclk_rates[] = { { .freq = 1296000000, .div = 1, }, { .freq = 1200000000, .div = 1, }, { .freq = 1104000000, .div = 1, }, { .freq = 1008000000, .div = 1, }, { .freq = 912000000, .div = 1, }, { .freq = 816000000, .div = 1, }, { .freq = 696000000, .div = 1, }, { .freq = 600000000, .div = 1, }, { .freq = 408000000, .div = 1, }, { .freq = 312000000, .div = 1, }, { .freq = 216000000, .div = 1, }, { .freq = 96000000, .div = 1, }, }; #define ARMCLK 6 static const char *armclk_parents[] = {"apll", "gpll", "dpll", "npll" }; static struct rk_clk_armclk_def armclk = { .clkdef = { .id = ARMCLK, .name = "armclk", .parent_names = armclk_parents, .parent_cnt = nitems(armclk_parents), }, .muxdiv_offset = 0x100, .mux_shift = 6, .mux_width = 2, .div_shift = 0, .div_width = 5, .flags = RK_CLK_COMPOSITE_HAVE_MUX, .main_parent = 3, /* npll */ .alt_parent = 0, /* apll */ .rates = rk3328_armclk_rates, .nrates = nitems(rk3328_armclk_rates), }; /* CRU_CLKSEL_CON1 */ #define PCLK_BUS_PRE 216 #define HCLK_BUS_PRE 328 static const char *hclk_bus_pre_parents[] = {"aclk_bus_pre"}; static struct rk_clk_composite_def hclk_bus_pre = { .clkdef = { .id = HCLK_BUS_PRE, .name = "hclk_bus_pre", .parent_names = hclk_bus_pre_parents, .parent_cnt = nitems(hclk_bus_pre_parents), }, .muxdiv_offset = 0x104, .div_shift = 8, .div_width = 2, .gate_offset = 0x220, .gate_shift = 1, .flags = RK_CLK_COMPOSITE_HAVE_GATE, }; static const char *pclk_bus_pre_parents[] = {"aclk_bus_pre"}; static struct rk_clk_composite_def pclk_bus_pre = { .clkdef = { .id = PCLK_BUS_PRE, .name = "pclk_bus_pre", .parent_names = pclk_bus_pre_parents, .parent_cnt = nitems(pclk_bus_pre_parents), }, .muxdiv_offset = 0x104, .div_shift = 12, .div_width = 3, .gate_offset = 0x220, .gate_shift = 2, .flags = RK_CLK_COMPOSITE_HAVE_GATE, }; /* CRU_CLKSEL_CON22 */ #define SCLK_TSADC 36 static const char *clk_tsadc_parents[] = {"xin24m"}; static struct rk_clk_composite_def clk_tsadc = { .clkdef = { .id = SCLK_TSADC, .name = "clk_tsadc", .parent_names = clk_tsadc_parents, .parent_cnt = nitems(clk_tsadc_parents), }, .div_shift = 0, .div_width = 9, }; /* CRU_CLKSEL_CON28 */ #define ACLK_PERI_PRE 137 static const char *aclk_peri_pre_parents[] = {"cpll", "gpll"/* , "hdmiphy" */}; static struct rk_clk_composite_def aclk_peri_pre = { .clkdef = { .id = ACLK_PERI_PRE, .name = "aclk_peri_pre", .parent_names = aclk_peri_pre_parents, .parent_cnt = nitems(aclk_peri_pre_parents), }, .muxdiv_offset = 0x170, .mux_shift = 6, .mux_width = 2, .div_shift = 0, .div_width = 5, .flags = RK_CLK_COMPOSITE_HAVE_MUX, }; /* CRU_CLKSEL_CON29 */ #define PCLK_PERI 230 #define HCLK_PERI 308 static const char *phclk_peri_parents[] = {"aclk_peri_pre"}; static struct rk_clk_composite_def pclk_peri = { .clkdef = { .id = PCLK_PERI, .name = "pclk_peri", .parent_names = phclk_peri_parents, .parent_cnt = nitems(phclk_peri_parents), }, .div_shift = 0, .div_width = 2, /* CRU_CLKGATE_CON10 */ .gate_offset = 0x228, .gate_shift = 2, .flags = RK_CLK_COMPOSITE_HAVE_GATE, }; static struct rk_clk_composite_def hclk_peri = { .clkdef = { .id = HCLK_PERI, .name = "hclk_peri", .parent_names = phclk_peri_parents, .parent_cnt = nitems(phclk_peri_parents), }, .div_shift = 4, .div_width = 3, /* CRU_CLKGATE_CON10 */ .gate_offset = 0x228, .gate_shift = 1, .flags = RK_CLK_COMPOSITE_HAVE_GATE, }; /* CRU_CLKSEL_CON30 */ #define SCLK_SDMMC 33 static const char *mmc_parents[] = {"cpll", "gpll", "xin24m"/* , "usb480m" */}; static struct rk_clk_composite_def sdmmc = { .clkdef = { .id = SCLK_SDMMC, .name = "clk_sdmmc", .parent_names = mmc_parents, .parent_cnt = nitems(mmc_parents), }, .muxdiv_offset = 0x178, .mux_shift = 8, .mux_width = 2, .div_shift = 0, .div_width = 8, /* CRU_CLKGATE_CON4 */ .gate_offset = 0x210, .gate_shift = 3, .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE, }; /* CRU_CLKSEL_CON31 */ #define SCLK_SDIO 34 static struct rk_clk_composite_def sdio = { .clkdef = { .id = SCLK_SDIO, .name = "clk_sdio", .parent_names = mmc_parents, .parent_cnt = nitems(mmc_parents), }, .muxdiv_offset = 0x17C, .mux_shift = 8, .mux_width = 2, .div_shift = 0, .div_width = 8, /* CRU_CLKGATE_CON4 */ .gate_offset = 0x210, .gate_shift = 4, .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE, }; /* CRU_CLKSEL_CON32 */ #define SCLK_EMMC 35 static struct rk_clk_composite_def emmc = { .clkdef = { .id = SCLK_EMMC, .name = "clk_emmc", .parent_names = mmc_parents, .parent_cnt = nitems(mmc_parents), }, .muxdiv_offset = 0x180, .mux_shift = 8, .mux_width = 2, .div_shift = 0, .div_width = 8, /* CRU_CLKGATE_CON4 */ .gate_offset = 0x210, .gate_shift = 5, .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE, }; /* CRU_CLKSEL_CON34 */ #define SCLK_I2C0 55 #define SCLK_I2C1 56 static const char *i2c_parents[] = {"cpll", "gpll"}; static struct rk_clk_composite_def i2c0 = { .clkdef = { .id = SCLK_I2C0, .name = "clk_i2c0", .parent_names = i2c_parents, .parent_cnt = nitems(i2c_parents), }, .muxdiv_offset = 0x188, .mux_shift = 7, .mux_width = 1, .div_shift = 0, .div_width = 6, /* CRU_CLKGATE_CON2 */ .gate_offset = 0x208, .gate_shift = 9, .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE, }; static struct rk_clk_composite_def i2c1 = { .clkdef = { .id = SCLK_I2C1, .name = "clk_i2c1", .parent_names = i2c_parents, .parent_cnt = nitems(i2c_parents), }, .muxdiv_offset = 0x188, .mux_shift = 15, .mux_width = 1, .div_shift = 8, .div_width = 6, /* CRU_CLKGATE_CON2 */ .gate_offset = 0x208, .gate_shift = 10, .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE, }; /* CRU_CLKSEL_CON35 */ #define SCLK_I2C2 57 #define SCLK_I2C3 58 static struct rk_clk_composite_def i2c2 = { .clkdef = { .id = SCLK_I2C2, .name = "clk_i2c2", .parent_names = i2c_parents, .parent_cnt = nitems(i2c_parents), }, .muxdiv_offset = 0x18C, .mux_shift = 7, .mux_width = 1, .div_shift = 0, .div_width = 6, /* CRU_CLKGATE_CON2 */ .gate_offset = 0x208, .gate_shift = 11, .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE, }; static struct rk_clk_composite_def i2c3 = { .clkdef = { .id = SCLK_I2C3, .name = "clk_i2c3", .parent_names = i2c_parents, .parent_cnt = nitems(i2c_parents), }, .muxdiv_offset = 0x18C, .mux_shift = 15, .mux_width = 1, .div_shift = 8, .div_width = 6, /* CRU_CLKGATE_CON2 */ .gate_offset = 0x208, .gate_shift = 12, .flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE, }; static struct rk_clk rk3328_clks[] = { { .type = RK3328_CLK_PLL, .clk.pll = &apll }, { .type = RK3328_CLK_PLL, .clk.pll = &dpll }, { .type = RK3328_CLK_PLL, .clk.pll = &cpll }, { .type = RK3328_CLK_PLL, .clk.pll = &gpll }, { .type = RK3328_CLK_PLL, .clk.pll = &npll }, { .type = RK_CLK_COMPOSITE, .clk.composite = &aclk_bus_pre }, { .type = RK_CLK_COMPOSITE, .clk.composite = &hclk_bus_pre }, { .type = RK_CLK_COMPOSITE, .clk.composite = &pclk_bus_pre }, { .type = RK_CLK_ARMCLK, .clk.armclk = &armclk, }, { .type = RK_CLK_COMPOSITE, .clk.composite = &clk_tsadc, }, { .type = RK_CLK_COMPOSITE, .clk.composite = &aclk_peri_pre, }, { .type = RK_CLK_COMPOSITE, .clk.composite = &pclk_peri, }, { .type = RK_CLK_COMPOSITE, .clk.composite = &hclk_peri, }, { .type = RK_CLK_COMPOSITE, .clk.composite = &sdmmc }, { .type = RK_CLK_COMPOSITE, .clk.composite = &sdio }, { .type = RK_CLK_COMPOSITE, .clk.composite = &emmc }, { .type = RK_CLK_COMPOSITE, .clk.composite = &i2c0 }, { .type = RK_CLK_COMPOSITE, .clk.composite = &i2c1 }, { .type = RK_CLK_COMPOSITE, .clk.composite = &i2c2 }, { .type = RK_CLK_COMPOSITE, .clk.composite = &i2c3 }, }; static int rk3328_cru_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_is_compatible(dev, "rockchip,rk3328-cru")) { device_set_desc(dev, "Rockchip RK3328 Clock and Reset Unit"); return (BUS_PROBE_DEFAULT); } return (ENXIO); } static int rk3328_cru_attach(device_t dev) { struct rk_cru_softc *sc; sc = device_get_softc(dev); sc->dev = dev; sc->gates = rk3328_gates; sc->ngates = nitems(rk3328_gates); sc->clks = rk3328_clks; sc->nclks = nitems(rk3328_clks); sc->reset_offset = 0x300; sc->reset_num = 184; return (rk_cru_attach(dev)); } static device_method_t rk3328_cru_methods[] = { /* Device interface */ DEVMETHOD(device_probe, rk3328_cru_probe), DEVMETHOD(device_attach, rk3328_cru_attach), DEVMETHOD_END }; static devclass_t rk3328_cru_devclass; DEFINE_CLASS_1(rk3328_cru, rk3328_cru_driver, rk3328_cru_methods, sizeof(struct rk_cru_softc), rk_cru_driver); EARLY_DRIVER_MODULE(rk3328_cru, simplebus, rk3328_cru_driver, rk3328_cru_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); Index: head/sys/arm64/rockchip/clk/rk_clk_armclk.c =================================================================== --- head/sys/arm64/rockchip/clk/rk_clk_armclk.c (revision 355356) +++ head/sys/arm64/rockchip/clk/rk_clk_armclk.c (revision 355357) @@ -1,258 +1,257 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include "clkdev_if.h" struct rk_clk_armclk_sc { uint32_t muxdiv_offset; uint32_t mux_shift; uint32_t mux_width; uint32_t mux_mask; uint32_t div_shift; uint32_t div_width; uint32_t div_mask; uint32_t gate_offset; uint32_t gate_shift; uint32_t flags; uint32_t main_parent; uint32_t alt_parent; struct rk_clk_armclk_rates *rates; int nrates; }; #define WRITE4(_clk, off, val) \ CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) #define READ4(_clk, off, val) \ CLKDEV_READ_4(clknode_get_device(_clk), off, val) #define DEVICE_LOCK(_clk) \ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) #define DEVICE_UNLOCK(_clk) \ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) #define RK_ARMCLK_WRITE_MASK_SHIFT 16 #if 0 #define dprintf(format, arg...) \ printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg) #else #define dprintf(format, arg...) #endif static int rk_clk_armclk_init(struct clknode *clk, device_t dev) { struct rk_clk_armclk_sc *sc; uint32_t val, idx; sc = clknode_get_softc(clk); idx = 0; DEVICE_LOCK(clk); READ4(clk, sc->muxdiv_offset, &val); DEVICE_UNLOCK(clk); idx = (val & sc->mux_mask) >> sc->mux_shift; clknode_init_parent_idx(clk, idx); return (0); } static int rk_clk_armclk_set_mux(struct clknode *clk, int index) { struct rk_clk_armclk_sc *sc; uint32_t val = 0; sc = clknode_get_softc(clk); dprintf("Set mux to %d\n", index); DEVICE_LOCK(clk); val |= index << sc->mux_shift; val |= sc->mux_mask << RK_ARMCLK_WRITE_MASK_SHIFT; dprintf("Write: muxdiv_offset=%x, val=%x\n", sc->muxdiv_offset, val); WRITE4(clk, sc->muxdiv_offset, val); DEVICE_UNLOCK(clk); return (0); } static int rk_clk_armclk_recalc(struct clknode *clk, uint64_t *freq) { struct rk_clk_armclk_sc *sc; uint32_t reg, div; sc = clknode_get_softc(clk); DEVICE_LOCK(clk); READ4(clk, sc->muxdiv_offset, ®); dprintf("Read: muxdiv_offset=%x, val=%x\n", sc->muxdiv_offset, reg); DEVICE_UNLOCK(clk); div = ((reg & sc->div_mask) >> sc->div_shift) + 1; dprintf("parent_freq=%ju, div=%u\n", *freq, div); *freq = *freq / div; return (0); } static int rk_clk_armclk_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout, int flags, int *stop) { struct rk_clk_armclk_sc *sc; struct clknode *p_main; const char **p_names; uint64_t best = 0, best_p = 0; uint32_t div = 0, val = 0; int err, i, rate = 0; sc = clknode_get_softc(clk); dprintf("Finding best parent/div for target freq of %ju\n", *fout); p_names = clknode_get_parent_names(clk); p_main = clknode_find_by_name(p_names[sc->main_parent]); for (i = 0; i < sc->nrates; i++) { if (sc->rates[i].freq == *fout) { best = sc->rates[i].freq; div = sc->rates[i].div; best_p = best * div; rate = i; dprintf("Best parent %s (%d) with best freq at %ju\n", clknode_get_name(p_main), sc->main_parent, best); break; } } if (rate == sc->nrates) return (0); if ((flags & CLK_SET_DRYRUN) != 0) { *fout = best; *stop = 1; return (0); } dprintf("Changing parent (%s) freq to %ju\n", clknode_get_name(p_main), best_p); err = clknode_set_freq(p_main, best_p, 0, 1); if (err != 0) printf("Cannot set %s to %ju\n", clknode_get_name(p_main), best_p); clknode_set_parent_by_idx(clk, sc->main_parent); clknode_get_freq(p_main, &best_p); dprintf("main parent freq at %ju\n", best_p); DEVICE_LOCK(clk); val |= (div - 1) << sc->div_shift; val |= sc->div_mask << RK_ARMCLK_WRITE_MASK_SHIFT; dprintf("Write: muxdiv_offset=%x, val=%x\n", sc->muxdiv_offset, val); WRITE4(clk, sc->muxdiv_offset, val); DEVICE_UNLOCK(clk); *fout = best; *stop = 1; return (0); } static clknode_method_t rk_clk_armclk_clknode_methods[] = { /* Device interface */ CLKNODEMETHOD(clknode_init, rk_clk_armclk_init), CLKNODEMETHOD(clknode_set_mux, rk_clk_armclk_set_mux), CLKNODEMETHOD(clknode_recalc_freq, rk_clk_armclk_recalc), CLKNODEMETHOD(clknode_set_freq, rk_clk_armclk_set_freq), CLKNODEMETHOD_END }; DEFINE_CLASS_1(rk_clk_armclk_clknode, rk_clk_armclk_clknode_class, rk_clk_armclk_clknode_methods, sizeof(struct rk_clk_armclk_sc), clknode_class); int rk_clk_armclk_register(struct clkdom *clkdom, struct rk_clk_armclk_def *clkdef) { struct clknode *clk; struct rk_clk_armclk_sc *sc; clk = clknode_create(clkdom, &rk_clk_armclk_clknode_class, &clkdef->clkdef); if (clk == NULL) return (1); sc = clknode_get_softc(clk); sc->muxdiv_offset = clkdef->muxdiv_offset; sc->mux_shift = clkdef->mux_shift; sc->mux_width = clkdef->mux_width; sc->mux_mask = ((1 << clkdef->mux_width) - 1) << sc->mux_shift; sc->div_shift = clkdef->div_shift; sc->div_width = clkdef->div_width; sc->div_mask = ((1 << clkdef->div_width) - 1) << sc->div_shift; sc->flags = clkdef->flags; sc->main_parent = clkdef->main_parent; sc->alt_parent = clkdef->alt_parent; sc->rates = clkdef->rates; sc->nrates = clkdef->nrates; clknode_register(clkdom, clk); return (0); } Index: head/sys/arm64/rockchip/clk/rk_clk_armclk.h =================================================================== --- head/sys/arm64/rockchip/clk/rk_clk_armclk.h (revision 355356) +++ head/sys/arm64/rockchip/clk/rk_clk_armclk.h (revision 355357) @@ -1,64 +1,63 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _RK_CLK_ARMCLK_H_ #define _RK_CLK_ARMCLK_H_ #include struct rk_clk_armclk_rates { uint64_t freq; uint32_t div; }; struct rk_clk_armclk_def { struct clknode_init_def clkdef; uint32_t muxdiv_offset; uint32_t mux_shift; uint32_t mux_width; uint32_t div_shift; uint32_t div_width; uint32_t flags; uint32_t main_parent; uint32_t alt_parent; struct rk_clk_armclk_rates *rates; int nrates; }; int rk_clk_armclk_register(struct clkdom *clkdom, struct rk_clk_armclk_def *clkdef); #endif /* _RK_CLK_ARMCLK_H_ */ Index: head/sys/arm64/rockchip/clk/rk_clk_composite.c =================================================================== --- head/sys/arm64/rockchip/clk/rk_clk_composite.c (revision 355356) +++ head/sys/arm64/rockchip/clk/rk_clk_composite.c (revision 355357) @@ -1,318 +1,317 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include "clkdev_if.h" struct rk_clk_composite_sc { uint32_t muxdiv_offset; uint32_t mux_shift; uint32_t mux_width; uint32_t mux_mask; uint32_t div_shift; uint32_t div_width; uint32_t div_mask; uint32_t gate_offset; uint32_t gate_shift; uint32_t flags; }; #define WRITE4(_clk, off, val) \ CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) #define READ4(_clk, off, val) \ CLKDEV_READ_4(clknode_get_device(_clk), off, val) #define DEVICE_LOCK(_clk) \ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) #define DEVICE_UNLOCK(_clk) \ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) #define RK_CLK_COMPOSITE_MASK_SHIFT 16 #if 0 #define dprintf(format, arg...) \ printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg) #else #define dprintf(format, arg...) #endif static int rk_clk_composite_init(struct clknode *clk, device_t dev) { struct rk_clk_composite_sc *sc; uint32_t val, idx; sc = clknode_get_softc(clk); idx = 0; if ((sc->flags & RK_CLK_COMPOSITE_HAVE_MUX) != 0) { DEVICE_LOCK(clk); READ4(clk, sc->muxdiv_offset, &val); DEVICE_UNLOCK(clk); idx = (val & sc->mux_mask) >> sc->mux_shift; } clknode_init_parent_idx(clk, idx); return (0); } static int rk_clk_composite_set_gate(struct clknode *clk, bool enable) { struct rk_clk_composite_sc *sc; uint32_t val = 0; sc = clknode_get_softc(clk); if ((sc->flags & RK_CLK_COMPOSITE_HAVE_GATE) == 0) return (0); dprintf("%sabling gate\n", enable ? "En" : "Dis"); if (!enable) val |= 1 << sc->gate_shift; dprintf("sc->gate_shift: %x\n", sc->gate_shift); val |= (1 << sc->gate_shift) << RK_CLK_COMPOSITE_MASK_SHIFT; dprintf("Write: gate_offset=%x, val=%x\n", sc->gate_offset, val); DEVICE_LOCK(clk); WRITE4(clk, sc->gate_offset, val); DEVICE_UNLOCK(clk); return (0); } static int rk_clk_composite_set_mux(struct clknode *clk, int index) { struct rk_clk_composite_sc *sc; uint32_t val = 0; sc = clknode_get_softc(clk); if ((sc->flags & RK_CLK_COMPOSITE_HAVE_MUX) == 0) return (0); dprintf("Set mux to %d\n", index); DEVICE_LOCK(clk); val |= (index << sc->mux_shift); val |= sc->mux_mask << RK_CLK_COMPOSITE_MASK_SHIFT; dprintf("Write: muxdiv_offset=%x, val=%x\n", sc->muxdiv_offset, val); WRITE4(clk, sc->muxdiv_offset, val); DEVICE_UNLOCK(clk); return (0); } static int rk_clk_composite_recalc(struct clknode *clk, uint64_t *freq) { struct rk_clk_composite_sc *sc; uint32_t reg, div; sc = clknode_get_softc(clk); DEVICE_LOCK(clk); READ4(clk, sc->muxdiv_offset, ®); dprintf("Read: muxdiv_offset=%x, val=%x\n", sc->muxdiv_offset, reg); DEVICE_UNLOCK(clk); div = ((reg & sc->div_mask) >> sc->div_shift); if (sc->flags & RK_CLK_COMPOSITE_DIV_EXP) div = 1 << div; else div += 1; dprintf("parent_freq=%ju, div=%u\n", *freq, div); *freq = *freq / div; dprintf("Final freq=%ju\n", *freq); return (0); } static uint32_t rk_clk_composite_find_best(struct rk_clk_composite_sc *sc, uint64_t fparent, uint64_t freq, uint32_t *reg) { uint64_t best, cur; uint32_t best_div, best_div_reg; uint32_t div, div_reg; best = 0; best_div = 0; best_div_reg = 0; for (div_reg = 0; div_reg <= ((sc->div_mask >> sc->div_shift) + 1); div_reg++) { if (sc->flags == RK_CLK_COMPOSITE_DIV_EXP) div = 1 << div_reg; else div = div_reg + 1; cur = fparent / div; if ((freq - cur) < (freq - best)) { best = cur; best_div = div; best_div_reg = div_reg; break; } } *reg = div_reg; return (best_div); } static int rk_clk_composite_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout, int flags, int *stop) { struct rk_clk_composite_sc *sc; struct clknode *p_clk; const char **p_names; uint64_t best, cur; uint32_t div, div_reg, best_div, best_div_reg, val; int p_idx, best_parent; sc = clknode_get_softc(clk); dprintf("Finding best parent/div for target freq of %ju\n", *fout); p_names = clknode_get_parent_names(clk); for (best_div = 0, best = 0, p_idx = 0; p_idx != clknode_get_parents_num(clk); p_idx++) { p_clk = clknode_find_by_name(p_names[p_idx]); clknode_get_freq(p_clk, &fparent); dprintf("Testing with parent %s (%d) at freq %ju\n", clknode_get_name(p_clk), p_idx, fparent); div = rk_clk_composite_find_best(sc, fparent, *fout, &div_reg); cur = fparent / div; if ((*fout - cur) < (*fout - best)) { best = cur; best_div = div; best_div_reg = div_reg; best_parent = p_idx; dprintf("Best parent so far %s (%d) with best freq at " "%ju\n", clknode_get_name(p_clk), p_idx, best); } } *stop = 1; if (best_div == 0) return (ERANGE); if ((best < *fout) && ((flags & CLK_SET_ROUND_DOWN) == 0)) return (ERANGE); if ((best > *fout) && ((flags & CLK_SET_ROUND_UP) == 0)) { return (ERANGE); } if ((flags & CLK_SET_DRYRUN) != 0) { *fout = best; return (0); } p_idx = clknode_get_parent_idx(clk); if (p_idx != best_parent) { dprintf("Switching parent index from %d to %d\n", p_idx, best_parent); clknode_set_parent_by_idx(clk, best_parent); } dprintf("Setting divider to %d (reg: %d)\n", best_div, best_div_reg); dprintf(" div_mask: 0x%X, div_shift: %d\n", sc->div_mask, sc->div_shift); DEVICE_LOCK(clk); val = best_div_reg << sc->div_shift; val |= sc->div_mask << RK_CLK_COMPOSITE_MASK_SHIFT; dprintf("Write: muxdiv_offset=%x, val=%x\n", sc->muxdiv_offset, val); WRITE4(clk, sc->muxdiv_offset, val); DEVICE_UNLOCK(clk); *fout = best; return (0); } static clknode_method_t rk_clk_composite_clknode_methods[] = { /* Device interface */ CLKNODEMETHOD(clknode_init, rk_clk_composite_init), CLKNODEMETHOD(clknode_set_gate, rk_clk_composite_set_gate), CLKNODEMETHOD(clknode_set_mux, rk_clk_composite_set_mux), CLKNODEMETHOD(clknode_recalc_freq, rk_clk_composite_recalc), CLKNODEMETHOD(clknode_set_freq, rk_clk_composite_set_freq), CLKNODEMETHOD_END }; DEFINE_CLASS_1(rk_clk_composite_clknode, rk_clk_composite_clknode_class, rk_clk_composite_clknode_methods, sizeof(struct rk_clk_composite_sc), clknode_class); int rk_clk_composite_register(struct clkdom *clkdom, struct rk_clk_composite_def *clkdef) { struct clknode *clk; struct rk_clk_composite_sc *sc; clk = clknode_create(clkdom, &rk_clk_composite_clknode_class, &clkdef->clkdef); if (clk == NULL) return (1); sc = clknode_get_softc(clk); sc->muxdiv_offset = clkdef->muxdiv_offset; sc->mux_shift = clkdef->mux_shift; sc->mux_width = clkdef->mux_width; sc->mux_mask = ((1 << clkdef->mux_width) - 1) << sc->mux_shift; sc->div_shift = clkdef->div_shift; sc->div_width = clkdef->div_width; sc->div_mask = ((1 << clkdef->div_width) - 1) << sc->div_shift; sc->gate_offset = clkdef->gate_offset; sc->gate_shift = clkdef->gate_shift; sc->flags = clkdef->flags; clknode_register(clkdom, clk); return (0); } Index: head/sys/arm64/rockchip/clk/rk_clk_composite.h =================================================================== --- head/sys/arm64/rockchip/clk/rk_clk_composite.h (revision 355356) +++ head/sys/arm64/rockchip/clk/rk_clk_composite.h (revision 355357) @@ -1,60 +1,59 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _RK_CLK_COMPOSITE_H_ #define _RK_CLK_COMPOSITE_H_ #include struct rk_clk_composite_def { struct clknode_init_def clkdef; uint32_t muxdiv_offset; uint32_t mux_shift; uint32_t mux_width; uint32_t div_shift; uint32_t div_width; uint32_t gate_offset; uint32_t gate_shift; uint32_t flags; }; #define RK_CLK_COMPOSITE_HAVE_MUX 0x0001 #define RK_CLK_COMPOSITE_HAVE_GATE 0x0002 #define RK_CLK_COMPOSITE_DIV_EXP 0x0004 /* Register 0, 1, 2, 2, ... */ /* Divider 1, 2, 4, 8, ... */ int rk_clk_composite_register(struct clkdom *clkdom, struct rk_clk_composite_def *clkdef); #endif /* _RK_CLK_COMPOSITE_H_ */ Index: head/sys/arm64/rockchip/clk/rk_clk_gate.h =================================================================== --- head/sys/arm64/rockchip/clk/rk_clk_gate.h (revision 355356) +++ head/sys/arm64/rockchip/clk/rk_clk_gate.h (revision 355357) @@ -1,50 +1,49 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _RK_CLK_GATE_H_ #define _RK_CLK_GATE_H_ #include struct rk_clk_gate_def { struct clknode_init_def clkdef; uint32_t offset; uint32_t shift; uint32_t mask; uint32_t on_value; uint32_t off_value; int gate_flags; }; #define RK_CLK_GATE_MASK 0xFFFF0000 int rk_clk_gate_register(struct clkdom *clkdom, struct rk_clk_gate_def *clkdef); #endif /* _RK_CLK_GATE_H_ */ Index: head/sys/arm64/rockchip/clk/rk_clk_pll.c =================================================================== --- head/sys/arm64/rockchip/clk/rk_clk_pll.c (revision 355356) +++ head/sys/arm64/rockchip/clk/rk_clk_pll.c (revision 355357) @@ -1,544 +1,543 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include "clkdev_if.h" struct rk_clk_pll_sc { uint32_t base_offset; uint32_t gate_offset; uint32_t gate_shift; uint32_t mode_reg; uint32_t mode_shift; uint32_t flags; struct rk_clk_pll_rate *rates; struct rk_clk_pll_rate *frac_rates; }; #define WRITE4(_clk, off, val) \ CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) #define READ4(_clk, off, val) \ CLKDEV_READ_4(clknode_get_device(_clk), off, val) #define DEVICE_LOCK(_clk) \ CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) #define DEVICE_UNLOCK(_clk) \ CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) #define RK_CLK_PLL_MASK_SHIFT 16 #if 0 #define dprintf(format, arg...) \ printf("%s:(%s)" format, __func__, clknode_get_name(clk), arg) #else #define dprintf(format, arg...) #endif static int rk_clk_pll_set_gate(struct clknode *clk, bool enable) { struct rk_clk_pll_sc *sc; uint32_t val = 0; sc = clknode_get_softc(clk); if ((sc->flags & RK_CLK_PLL_HAVE_GATE) == 0) return (0); dprintf("%sabling gate\n", enable ? "En" : "Dis"); if (!enable) val |= 1 << sc->gate_shift; dprintf("sc->gate_shift: %x\n", sc->gate_shift); val |= (1 << sc->gate_shift) << RK_CLK_PLL_MASK_SHIFT; dprintf("Write: gate_offset=%x, val=%x\n", sc->gate_offset, val); DEVICE_LOCK(clk); WRITE4(clk, sc->gate_offset, val); DEVICE_UNLOCK(clk); return (0); } #define RK3328_CLK_PLL_FBDIV_OFFSET 0 #define RK3328_CLK_PLL_FBDIV_SHIFT 0 #define RK3328_CLK_PLL_FBDIV_MASK 0xFFF #define RK3328_CLK_PLL_POSTDIV1_OFFSET 0 #define RK3328_CLK_PLL_POSTDIV1_SHIFT 12 #define RK3328_CLK_PLL_POSTDIV1_MASK 0x7000 #define RK3328_CLK_PLL_DSMPD_OFFSET 4 #define RK3328_CLK_PLL_DSMPD_SHIFT 12 #define RK3328_CLK_PLL_DSMPD_MASK 0x1000 #define RK3328_CLK_PLL_REFDIV_OFFSET 4 #define RK3328_CLK_PLL_REFDIV_SHIFT 0 #define RK3328_CLK_PLL_REFDIV_MASK 0x3F #define RK3328_CLK_PLL_POSTDIV2_OFFSET 4 #define RK3328_CLK_PLL_POSTDIV2_SHIFT 6 #define RK3328_CLK_PLL_POSTDIV2_MASK 0x1C0 #define RK3328_CLK_PLL_FRAC_OFFSET 8 #define RK3328_CLK_PLL_FRAC_SHIFT 0 #define RK3328_CLK_PLL_FRAC_MASK 0xFFFFFF #define RK3328_CLK_PLL_LOCK_MASK 0x400 #define RK3328_CLK_PLL_MODE_SLOW 0 #define RK3328_CLK_PLL_MODE_NORMAL 1 #define RK3328_CLK_PLL_MODE_MASK 0x1 static int rk3328_clk_pll_init(struct clknode *clk, device_t dev) { struct rk_clk_pll_sc *sc; sc = clknode_get_softc(clk); clknode_init_parent_idx(clk, 0); return (0); } static int rk3328_clk_pll_recalc(struct clknode *clk, uint64_t *freq) { struct rk_clk_pll_sc *sc; uint64_t rate; uint32_t dsmpd, refdiv, fbdiv; uint32_t postdiv1, postdiv2, frac; uint32_t raw1, raw2, raw3; sc = clknode_get_softc(clk); DEVICE_LOCK(clk); READ4(clk, sc->base_offset, &raw1); READ4(clk, sc->base_offset + 4, &raw2); READ4(clk, sc->base_offset + 8, &raw3); fbdiv = (raw1 & RK3328_CLK_PLL_FBDIV_MASK) >> RK3328_CLK_PLL_FBDIV_SHIFT; postdiv1 = (raw1 & RK3328_CLK_PLL_POSTDIV1_MASK) >> RK3328_CLK_PLL_POSTDIV1_SHIFT; dsmpd = (raw2 & RK3328_CLK_PLL_DSMPD_MASK) >> RK3328_CLK_PLL_DSMPD_SHIFT; refdiv = (raw2 & RK3328_CLK_PLL_REFDIV_MASK) >> RK3328_CLK_PLL_REFDIV_SHIFT; postdiv2 = (raw2 & RK3328_CLK_PLL_POSTDIV2_MASK) >> RK3328_CLK_PLL_POSTDIV2_SHIFT; frac = (raw3 & RK3328_CLK_PLL_FRAC_MASK) >> RK3328_CLK_PLL_FRAC_SHIFT; DEVICE_UNLOCK(clk); rate = *freq * fbdiv / refdiv; if (dsmpd == 0) { /* Fractional mode */ uint64_t frac_rate; frac_rate = *freq * frac / refdiv; rate += frac_rate >> 24; } *freq = rate / postdiv1 / postdiv2; if (*freq % 2) *freq = *freq + 1; return (0); } static int rk3328_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout, int flags, int *stop) { struct rk_clk_pll_rate *rates; struct rk_clk_pll_sc *sc; uint32_t reg; int timeout; sc = clknode_get_softc(clk); if (sc->rates) rates = sc->rates; else if (sc->frac_rates) rates = sc->frac_rates; else return (EINVAL); for (; rates->freq; rates++) { if (rates->freq == *fout) break; } if (rates->freq == 0) { *stop = 1; return (EINVAL); } DEVICE_LOCK(clk); /* Setting to slow mode during frequency change */ reg = (RK3328_CLK_PLL_MODE_MASK << sc->mode_shift) << RK_CLK_PLL_MASK_SHIFT; dprintf("Set PLL_MODEREG to %x\n", reg); WRITE4(clk, sc->mode_reg, reg); /* Setting postdiv1 and fbdiv */ reg = (rates->postdiv1 << RK3328_CLK_PLL_POSTDIV1_SHIFT) | (rates->fbdiv << RK3328_CLK_PLL_FBDIV_SHIFT); reg |= (RK3328_CLK_PLL_POSTDIV1_MASK | RK3328_CLK_PLL_FBDIV_MASK) << 16; dprintf("Set PLL_CON0 to %x\n", reg); WRITE4(clk, sc->base_offset, reg); /* Setting dsmpd, postdiv2 and refdiv */ reg = (rates->dsmpd << RK3328_CLK_PLL_DSMPD_SHIFT) | (rates->postdiv2 << RK3328_CLK_PLL_POSTDIV2_SHIFT) | (rates->refdiv << RK3328_CLK_PLL_REFDIV_SHIFT); reg |= (RK3328_CLK_PLL_DSMPD_MASK | RK3328_CLK_PLL_POSTDIV2_MASK | RK3328_CLK_PLL_REFDIV_MASK) << RK_CLK_PLL_MASK_SHIFT; dprintf("Set PLL_CON1 to %x\n", reg); WRITE4(clk, sc->base_offset + 0x4, reg); /* Setting frac */ READ4(clk, sc->base_offset + 0x8, ®); reg &= ~RK3328_CLK_PLL_FRAC_MASK; reg |= rates->frac << RK3328_CLK_PLL_FRAC_SHIFT; dprintf("Set PLL_CON2 to %x\n", reg); WRITE4(clk, sc->base_offset + 0x8, reg); /* Reading lock */ for (timeout = 1000; timeout; timeout--) { READ4(clk, sc->base_offset + 0x4, ®); if ((reg & RK3328_CLK_PLL_LOCK_MASK) == 0) break; DELAY(1); } /* Set back to normal mode */ reg = (RK3328_CLK_PLL_MODE_NORMAL << sc->mode_shift); reg |= (RK3328_CLK_PLL_MODE_MASK << sc->mode_shift) << RK_CLK_PLL_MASK_SHIFT; dprintf("Set PLL_MODEREG to %x\n", reg); WRITE4(clk, sc->mode_reg, reg); DEVICE_UNLOCK(clk); *stop = 1; return (0); } static clknode_method_t rk3328_clk_pll_clknode_methods[] = { /* Device interface */ CLKNODEMETHOD(clknode_init, rk3328_clk_pll_init), CLKNODEMETHOD(clknode_set_gate, rk_clk_pll_set_gate), CLKNODEMETHOD(clknode_recalc_freq, rk3328_clk_pll_recalc), CLKNODEMETHOD(clknode_set_freq, rk3328_clk_pll_set_freq), CLKNODEMETHOD_END }; DEFINE_CLASS_1(rk3328_clk_pll_clknode, rk3328_clk_pll_clknode_class, rk3328_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class); int rk3328_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef) { struct clknode *clk; struct rk_clk_pll_sc *sc; clk = clknode_create(clkdom, &rk3328_clk_pll_clknode_class, &clkdef->clkdef); if (clk == NULL) return (1); sc = clknode_get_softc(clk); sc->base_offset = clkdef->base_offset; sc->gate_offset = clkdef->gate_offset; sc->gate_shift = clkdef->gate_shift; sc->mode_reg = clkdef->mode_reg; sc->mode_shift = clkdef->mode_shift; sc->flags = clkdef->flags; sc->rates = clkdef->rates; sc->frac_rates = clkdef->frac_rates; clknode_register(clkdom, clk); return (0); } #define RK3399_CLK_PLL_FBDIV_OFFSET 0 #define RK3399_CLK_PLL_FBDIV_SHIFT 0 #define RK3399_CLK_PLL_FBDIV_MASK 0xFFF #define RK3399_CLK_PLL_POSTDIV2_OFFSET 4 #define RK3399_CLK_PLL_POSTDIV2_SHIFT 12 #define RK3399_CLK_PLL_POSTDIV2_MASK 0x7000 #define RK3399_CLK_PLL_POSTDIV1_OFFSET 4 #define RK3399_CLK_PLL_POSTDIV1_SHIFT 8 #define RK3399_CLK_PLL_POSTDIV1_MASK 0x700 #define RK3399_CLK_PLL_REFDIV_OFFSET 4 #define RK3399_CLK_PLL_REFDIV_SHIFT 0 #define RK3399_CLK_PLL_REFDIV_MASK 0x3F #define RK3399_CLK_PLL_FRAC_OFFSET 8 #define RK3399_CLK_PLL_FRAC_SHIFT 0 #define RK3399_CLK_PLL_FRAC_MASK 0xFFFFFF #define RK3399_CLK_PLL_DSMPD_OFFSET 0xC #define RK3399_CLK_PLL_DSMPD_SHIFT 3 #define RK3399_CLK_PLL_DSMPD_MASK 0x8 #define RK3399_CLK_PLL_LOCK_OFFSET 8 #define RK3399_CLK_PLL_LOCK_MASK 0x400 #define RK3399_CLK_PLL_MODE_OFFSET 0xC #define RK3399_CLK_PLL_MODE_MASK 0x300 #define RK3399_CLK_PLL_MODE_SLOW 0 #define RK3399_CLK_PLL_MODE_NORMAL 1 #define RK3399_CLK_PLL_MODE_DEEPSLOW 2 #define RK3399_CLK_PLL_MODE_SHIFT 8 #define RK3399_CLK_PLL_WRITE_MASK 0xFFFF0000 static int rk3399_clk_pll_init(struct clknode *clk, device_t dev) { struct rk_clk_pll_sc *sc; sc = clknode_get_softc(clk); clknode_init_parent_idx(clk, 0); return (0); } static int rk3399_clk_pll_recalc(struct clknode *clk, uint64_t *freq) { struct rk_clk_pll_sc *sc; uint32_t dsmpd, refdiv, fbdiv; uint32_t postdiv1, postdiv2, fracdiv; uint32_t con1, con2, con3, con4; uint64_t foutvco; uint32_t mode; sc = clknode_get_softc(clk); DEVICE_LOCK(clk); READ4(clk, sc->base_offset, &con1); READ4(clk, sc->base_offset + 4, &con2); READ4(clk, sc->base_offset + 8, &con3); READ4(clk, sc->base_offset + 0xC, &con4); DEVICE_UNLOCK(clk); /* * if we are in slow mode the output freq * is the parent one, the 24Mhz external oscillator * if we are in deep mode the output freq is 32.768khz */ mode = (con4 & RK3399_CLK_PLL_MODE_MASK) >> RK3399_CLK_PLL_MODE_SHIFT; if (mode == RK3399_CLK_PLL_MODE_SLOW) { dprintf("pll in slow mode, con4=%x\n", con4); return (0); } else if (mode == RK3399_CLK_PLL_MODE_DEEPSLOW) { dprintf("pll in deep slow, con4=%x\n", con4); *freq = 32768; return (0); } dprintf("con0: %x\n", con1); dprintf("con1: %x\n", con2); dprintf("con2: %x\n", con3); dprintf("con3: %x\n", con4); fbdiv = (con1 & RK3399_CLK_PLL_FBDIV_MASK) >> RK3399_CLK_PLL_FBDIV_SHIFT; postdiv1 = (con2 & RK3399_CLK_PLL_POSTDIV1_MASK) >> RK3399_CLK_PLL_POSTDIV1_SHIFT; postdiv2 = (con2 & RK3399_CLK_PLL_POSTDIV2_MASK) >> RK3399_CLK_PLL_POSTDIV2_SHIFT; refdiv = (con2 & RK3399_CLK_PLL_REFDIV_MASK) >> RK3399_CLK_PLL_REFDIV_SHIFT; fracdiv = (con3 & RK3399_CLK_PLL_FRAC_MASK) >> RK3399_CLK_PLL_FRAC_SHIFT; fracdiv >>= 24; dsmpd = (con4 & RK3399_CLK_PLL_DSMPD_MASK) >> RK3399_CLK_PLL_DSMPD_SHIFT; dprintf("fbdiv: %d\n", fbdiv); dprintf("postdiv1: %d\n", postdiv1); dprintf("postdiv2: %d\n", postdiv2); dprintf("refdiv: %d\n", refdiv); dprintf("fracdiv: %d\n", fracdiv); dprintf("dsmpd: %d\n", dsmpd); dprintf("parent freq=%ju\n", *freq); if (dsmpd == 0) { /* Fractional mode */ foutvco = *freq / refdiv * (fbdiv + fracdiv); } else { /* Integer mode */ foutvco = *freq / refdiv * fbdiv; } dprintf("foutvco: %ju\n", foutvco); *freq = foutvco / postdiv1 / postdiv2; dprintf("freq: %ju\n", *freq); return (0); } static int rk3399_clk_pll_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout, int flags, int *stop) { struct rk_clk_pll_rate *rates; struct rk_clk_pll_sc *sc; uint32_t reg; int timeout; sc = clknode_get_softc(clk); if (sc->rates) rates = sc->rates; else if (sc->frac_rates) rates = sc->frac_rates; else return (EINVAL); for (; rates->freq; rates++) { if (rates->freq == *fout) break; } if (rates->freq == 0) { *stop = 1; return (EINVAL); } DEVICE_LOCK(clk); /* Set to slow mode during frequency change */ reg = RK3399_CLK_PLL_MODE_SLOW << RK3399_CLK_PLL_MODE_SHIFT; reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT; WRITE4(clk, sc->base_offset + 0xC, reg); /* Setting fbdiv */ reg = rates->fbdiv << RK3399_CLK_PLL_FBDIV_SHIFT; reg |= RK3399_CLK_PLL_FBDIV_MASK << RK_CLK_PLL_MASK_SHIFT; WRITE4(clk, sc->base_offset, reg); /* Setting postdiv1, postdiv2 and refdiv */ reg = rates->postdiv1 << RK3399_CLK_PLL_POSTDIV1_SHIFT; reg |= rates->postdiv2 << RK3399_CLK_PLL_POSTDIV2_SHIFT; reg |= rates->refdiv << RK3399_CLK_PLL_REFDIV_SHIFT; reg |= (RK3399_CLK_PLL_POSTDIV1_MASK | RK3399_CLK_PLL_POSTDIV2_MASK | RK3399_CLK_PLL_REFDIV_MASK) << RK_CLK_PLL_MASK_SHIFT; WRITE4(clk, sc->base_offset + 0x4, reg); /* Setting frac */ READ4(clk, sc->base_offset + 0x8, ®); reg &= ~RK3399_CLK_PLL_FRAC_MASK; reg |= rates->frac << RK3399_CLK_PLL_FRAC_SHIFT; WRITE4(clk, sc->base_offset + 0x8, reg | RK3399_CLK_PLL_WRITE_MASK); /* Set dsmpd */ reg = rates->dsmpd << RK3399_CLK_PLL_DSMPD_SHIFT; reg |= RK3399_CLK_PLL_DSMPD_MASK << RK_CLK_PLL_MASK_SHIFT; WRITE4(clk, sc->base_offset + 0xC, reg); /* Reading lock */ for (timeout = 1000; timeout; timeout--) { READ4(clk, sc->base_offset + RK3399_CLK_PLL_LOCK_OFFSET, ®); if ((reg & RK3399_CLK_PLL_LOCK_MASK) == 0) break; DELAY(1); } /* Set back to normal mode */ reg = RK3399_CLK_PLL_MODE_NORMAL << RK3399_CLK_PLL_MODE_SHIFT; reg |= RK3399_CLK_PLL_MODE_MASK << RK_CLK_PLL_MASK_SHIFT; WRITE4(clk, sc->base_offset + 0xC, reg); DEVICE_UNLOCK(clk); *stop = 1; return (0); } static clknode_method_t rk3399_clk_pll_clknode_methods[] = { /* Device interface */ CLKNODEMETHOD(clknode_init, rk3399_clk_pll_init), CLKNODEMETHOD(clknode_set_gate, rk_clk_pll_set_gate), CLKNODEMETHOD(clknode_recalc_freq, rk3399_clk_pll_recalc), CLKNODEMETHOD(clknode_set_freq, rk3399_clk_pll_set_freq), CLKNODEMETHOD_END }; DEFINE_CLASS_1(rk3399_clk_pll_clknode, rk3399_clk_pll_clknode_class, rk3399_clk_pll_clknode_methods, sizeof(struct rk_clk_pll_sc), clknode_class); int rk3399_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef) { struct clknode *clk; struct rk_clk_pll_sc *sc; clk = clknode_create(clkdom, &rk3399_clk_pll_clknode_class, &clkdef->clkdef); if (clk == NULL) return (1); sc = clknode_get_softc(clk); sc->base_offset = clkdef->base_offset; sc->gate_offset = clkdef->gate_offset; sc->gate_shift = clkdef->gate_shift; sc->flags = clkdef->flags; sc->rates = clkdef->rates; sc->frac_rates = clkdef->frac_rates; clknode_register(clkdom, clk); return (0); } Index: head/sys/arm64/rockchip/clk/rk_clk_pll.h =================================================================== --- head/sys/arm64/rockchip/clk/rk_clk_pll.h (revision 355356) +++ head/sys/arm64/rockchip/clk/rk_clk_pll.h (revision 355357) @@ -1,67 +1,66 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _RK_CLK_PLL_H_ #define _RK_CLK_PLL_H_ #include struct rk_clk_pll_rate { uint32_t freq; uint32_t refdiv; uint32_t fbdiv; uint32_t postdiv1; uint32_t postdiv2; uint32_t dsmpd; uint32_t frac; }; struct rk_clk_pll_def { struct clknode_init_def clkdef; uint32_t base_offset; uint32_t gate_offset; uint32_t gate_shift; uint32_t mode_reg; uint32_t mode_shift; uint32_t flags; struct rk_clk_pll_rate *rates; struct rk_clk_pll_rate *frac_rates; }; #define RK_CLK_PLL_HAVE_GATE 0x1 int rk3328_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef); int rk3399_clk_pll_register(struct clkdom *clkdom, struct rk_clk_pll_def *clkdef); #endif /* _RK_CLK_PLL_H_ */ Index: head/sys/arm64/rockchip/clk/rk_cru.c =================================================================== --- head/sys/arm64/rockchip/clk/rk_cru.c (revision 355356) +++ head/sys/arm64/rockchip/clk/rk_cru.c (revision 355357) @@ -1,307 +1,306 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * RockChip Clock and Reset Unit */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "clkdev_if.h" #include "hwreset_if.h" static struct resource_spec rk_cru_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { -1, 0 } }; #define CCU_READ4(sc, reg) bus_read_4((sc)->res, (reg)) #define CCU_WRITE4(sc, reg, val) bus_write_4((sc)->res, (reg), (val)) void rk3328_cru_register_clocks(struct rk_cru_softc *sc); static int rk_cru_write_4(device_t dev, bus_addr_t addr, uint32_t val) { struct rk_cru_softc *sc; sc = device_get_softc(dev); CCU_WRITE4(sc, addr, val); return (0); } static int rk_cru_read_4(device_t dev, bus_addr_t addr, uint32_t *val) { struct rk_cru_softc *sc; sc = device_get_softc(dev); *val = CCU_READ4(sc, addr); return (0); } static int rk_cru_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set) { struct rk_cru_softc *sc; uint32_t reg; sc = device_get_softc(dev); reg = CCU_READ4(sc, addr); reg &= ~clr; reg |= set; CCU_WRITE4(sc, addr, reg); return (0); } static int rk_cru_reset_assert(device_t dev, intptr_t id, bool reset) { struct rk_cru_softc *sc; uint32_t reg; int bit; uint32_t val; sc = device_get_softc(dev); if (id > sc->reset_num) return (ENXIO); reg = sc->reset_offset + id / 16 * 4; bit = id % 16; mtx_lock(&sc->mtx); val = 0; if (reset) val = (1 << bit); CCU_WRITE4(sc, reg, val | ((1 << bit) << 16)); mtx_unlock(&sc->mtx); return (0); } static int rk_cru_reset_is_asserted(device_t dev, intptr_t id, bool *reset) { struct rk_cru_softc *sc; uint32_t reg; int bit; uint32_t val; sc = device_get_softc(dev); if (id > sc->reset_num) return (ENXIO); reg = sc->reset_offset + id / 16 * 4; bit = id % 16; mtx_lock(&sc->mtx); val = CCU_READ4(sc, reg); mtx_unlock(&sc->mtx); *reset = false; if (val & (1 << bit)) *reset = true; return (0); } static void rk_cru_device_lock(device_t dev) { struct rk_cru_softc *sc; sc = device_get_softc(dev); mtx_lock(&sc->mtx); } static void rk_cru_device_unlock(device_t dev) { struct rk_cru_softc *sc; sc = device_get_softc(dev); mtx_unlock(&sc->mtx); } static int rk_cru_register_gates(struct rk_cru_softc *sc) { struct rk_clk_gate_def def; int i; for (i = 0; i < sc->ngates; i++) { if (sc->gates[i].name == NULL) continue; memset(&def, 0, sizeof(def)); def.clkdef.id = sc->gates[i].id; def.clkdef.name = sc->gates[i].name; def.clkdef.parent_names = &sc->gates[i].parent_name; def.clkdef.parent_cnt = 1; def.offset = sc->gates[i].offset; def.shift = sc->gates[i].shift; def.mask = 1; def.on_value = 0; def.off_value = 1; rk_clk_gate_register(sc->clkdom, &def); } return (0); } int rk_cru_attach(device_t dev) { struct rk_cru_softc *sc; phandle_t node; int i; sc = device_get_softc(dev); sc->dev = dev; node = ofw_bus_get_node(dev); if (bus_alloc_resources(dev, rk_cru_spec, &sc->res) != 0) { device_printf(dev, "cannot allocate resources for device\n"); return (ENXIO); } mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); sc->clkdom = clkdom_create(dev); if (sc->clkdom == NULL) panic("Cannot create clkdom\n"); for (i = 0; i < sc->nclks; i++) { switch (sc->clks[i].type) { case RK_CLK_UNDEFINED: break; case RK3328_CLK_PLL: rk3328_clk_pll_register(sc->clkdom, sc->clks[i].clk.pll); break; case RK3399_CLK_PLL: rk3399_clk_pll_register(sc->clkdom, sc->clks[i].clk.pll); break; case RK_CLK_COMPOSITE: rk_clk_composite_register(sc->clkdom, sc->clks[i].clk.composite); break; case RK_CLK_MUX: rk_clk_mux_register(sc->clkdom, sc->clks[i].clk.mux); break; case RK_CLK_ARMCLK: rk_clk_armclk_register(sc->clkdom, sc->clks[i].clk.armclk); break; case RK_CLK_FIXED: clknode_fixed_register(sc->clkdom, sc->clks[i].clk.fixed); break; case RK_CLK_FRACT: rk_clk_fract_register(sc->clkdom, sc->clks[i].clk.fract); break; case RK_CLK_LINK: clknode_link_register(sc->clkdom, sc->clks[i].clk.link); break; default: device_printf(dev, "Unknown clock type\n"); return (ENXIO); } } if (sc->gates) rk_cru_register_gates(sc); if (clkdom_finit(sc->clkdom) != 0) panic("cannot finalize clkdom initialization\n"); if (bootverbose) clkdom_dump(sc->clkdom); clk_set_assigned(dev, node); /* register our self as a reset provider */ hwreset_register_ofw_provider(dev); return (0); } static device_method_t rk_cru_methods[] = { /* clkdev interface */ DEVMETHOD(clkdev_write_4, rk_cru_write_4), DEVMETHOD(clkdev_read_4, rk_cru_read_4), DEVMETHOD(clkdev_modify_4, rk_cru_modify_4), DEVMETHOD(clkdev_device_lock, rk_cru_device_lock), DEVMETHOD(clkdev_device_unlock, rk_cru_device_unlock), /* Reset interface */ DEVMETHOD(hwreset_assert, rk_cru_reset_assert), DEVMETHOD(hwreset_is_asserted, rk_cru_reset_is_asserted), DEVMETHOD_END }; DEFINE_CLASS_0(rk_cru, rk_cru_driver, rk_cru_methods, sizeof(struct rk_cru_softc)); Index: head/sys/arm64/rockchip/clk/rk_cru.h =================================================================== --- head/sys/arm64/rockchip/clk/rk_cru.h (revision 355356) +++ head/sys/arm64/rockchip/clk/rk_cru.h (revision 355357) @@ -1,253 +1,252 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef __RK_CRU_H__ #define __RK_CRU_H__ #include #include #include #include #include #include #include #include #include #include #include /* Macro for defining various types of clocks. */ /* Pure gate */ #define GATE(_idx, _clkname, _pname, _o, _s) \ { \ .id = _idx, \ .name = _clkname, \ .parent_name = _pname, \ .offset = CRU_CLKGATE_CON(_o), \ .shift = _s, \ } /* Fixed rate clock. */ #define FRATE(_id, _name, _freq) \ { \ .type = RK_CLK_FIXED, \ .clk.fixed = &(struct clk_fixed_def) { \ .clkdef.id = _id, \ .clkdef.name = _name, \ .clkdef.parent_names = NULL, \ .clkdef.parent_cnt = 0, \ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ .freq = _freq, \ }, \ } /* Fixed factor multipier/divider. */ #define FFACT(_id, _name, _pname, _mult, _div) \ { \ .type = RK_CLK_FIXED, \ .clk.fixed = &(struct clk_fixed_def) { \ .clkdef.id = _id, \ .clkdef.name = _name, \ .clkdef.parent_names = (const char *[]){_pname}, \ .clkdef.parent_cnt = 1, \ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ .mult = _mult, \ .div = _div, \ }, \ } /* Linked clock. */ #define LINK(_name) \ { \ .type = RK_CLK_LINK, \ .clk.link = &(struct clk_link_def) { \ .clkdef.id = 0, \ .clkdef.name = _name, \ .clkdef.parent_names = NULL, \ .clkdef.parent_cnt = 0, \ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ }, \ } /* Complex clock fo ARM cores. */ #define ARMDIV(_id, _name, _pn, _r, _o, _ds, _dw, _ms, _mw, _mp, _ap) \ { \ .type = RK_CLK_ARMCLK, \ .clk.armclk = &(struct rk_clk_armclk_def) { \ .clkdef.id = _id, \ .clkdef.name = _name, \ .clkdef.parent_names = _pn, \ .clkdef.parent_cnt = nitems(_pn), \ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ .muxdiv_offset = CRU_CLKSEL_CON(_o), \ .mux_shift = _ms, \ .mux_width = _mw, \ .div_shift = _ds, \ .div_width = _dw, \ .main_parent = _mp, \ .alt_parent = _ap, \ .rates = _r, \ .nrates = nitems(_r), \ }, \ } /* Fractional rate multipier/divider. */ #define FRACT(_id, _name, _pname, _f, _o) \ { \ .type = RK_CLK_FRACT, \ .clk.fract = &(struct rk_clk_fract_def) { \ .clkdef.id = _id, \ .clkdef.name = _name, \ .clkdef.parent_names = (const char *[]){_pname}, \ .clkdef.parent_cnt = 1, \ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ .offset = CRU_CLKSEL_CON(_o), \ .flags = _f, \ }, \ } /* Full composite clock. */ #define COMP(_id, _name, _pnames, _f, _o, _ds, _dw, _ms, _mw) \ { \ .type = RK_CLK_COMPOSITE, \ .clk.composite = &(struct rk_clk_composite_def) { \ .clkdef.id = _id, \ .clkdef.name = _name, \ .clkdef.parent_names = _pnames, \ .clkdef.parent_cnt = nitems(_pnames), \ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ .muxdiv_offset = CRU_CLKSEL_CON(_o), \ .mux_shift = _ms, \ .mux_width = _mw, \ .div_shift = _ds, \ .div_width = _dw, \ .flags = RK_CLK_COMPOSITE_HAVE_MUX | _f, \ }, \ } /* Composite clock without mux (divider only). */ #define CDIV(_id, _name, _pname, _f, _o, _ds, _dw) \ { \ .type = RK_CLK_COMPOSITE, \ .clk.composite = &(struct rk_clk_composite_def) { \ .clkdef.id = _id, \ .clkdef.name = _name, \ .clkdef.parent_names = (const char *[]){_pname}, \ .clkdef.parent_cnt = 1, \ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ .muxdiv_offset = CRU_CLKSEL_CON(_o), \ .div_shift = _ds, \ .div_width = _dw, \ .flags = _f, \ }, \ } /* Complex clock without divider (multiplexer only). */ #define MUX(_id, _name, _pn, _f, _mo, _ms, _mw) \ { \ .type = RK_CLK_MUX, \ .clk.mux = &(struct rk_clk_mux_def) { \ .clkdef.id = _id, \ .clkdef.name = _name, \ .clkdef.parent_names = _pn, \ .clkdef.parent_cnt = nitems(_pn), \ .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ .offset = CRU_CLKSEL_CON(_mo), \ .shift = _ms, \ .width = _mw, \ .mux_flags = _f, \ }, \ } struct rk_cru_gate { const char *name; const char *parent_name; uint32_t id; uint32_t offset; uint32_t shift; }; #define CRU_GATE(idx, clkname, pname, o, s) \ { \ .id = idx, \ .name = clkname, \ .parent_name = pname, \ .offset = o, \ .shift = s, \ }, enum rk_clk_type { RK_CLK_UNDEFINED = 0, RK3328_CLK_PLL, RK3399_CLK_PLL, RK_CLK_COMPOSITE, RK_CLK_FIXED, RK_CLK_FRACT, RK_CLK_MUX, RK_CLK_ARMCLK, RK_CLK_LINK, }; struct rk_clk { enum rk_clk_type type; union { struct rk_clk_pll_def *pll; struct rk_clk_composite_def *composite; struct rk_clk_mux_def *mux; struct rk_clk_armclk_def *armclk; struct clk_fixed_def *fixed; struct rk_clk_fract_def *fract; struct clk_link_def *link; } clk; }; struct rk_cru_softc { device_t dev; struct resource *res; struct clkdom *clkdom; struct mtx mtx; int type; uint32_t reset_offset; uint32_t reset_num; struct rk_cru_gate *gates; int ngates; struct rk_clk *clks; int nclks; struct rk_clk_armclk_def *armclk; struct rk_clk_armclk_rates *armclk_rates; int narmclk_rates; }; DECLARE_CLASS(rk_cru_driver); int rk_cru_attach(device_t dev); #endif /* __RK_CRU_H__ */ Index: head/sys/arm64/rockchip/if_dwc_rk.c =================================================================== --- head/sys/arm64/rockchip/if_dwc_rk.c (revision 355356) +++ head/sys/arm64/rockchip/if_dwc_rk.c (revision 355357) @@ -1,192 +1,191 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include "syscon_if.h" #include "if_dwc_if.h" #define RK3328_GRF_MAC_CON0 0x0900 #define RK3328_GRF_MAC_CON0_TX_MASK 0x7F #define RK3328_GRF_MAC_CON0_TX_SHIFT 0 #define RK3328_GRF_MAC_CON0_RX_MASK 0x7F #define RK3328_GRF_MAC_CON0_RX_SHIFT 7 #define RK3328_GRF_MAC_CON1 0x0904 #define RK3328_GRF_MAC_CON2 0x0908 #define RK3328_GRF_MACPHY_CON0 0x0B00 #define RK3328_GRF_MACPHY_CON1 0x0B04 #define RK3328_GRF_MACPHY_CON2 0x0B08 #define RK3328_GRF_MACPHY_CON3 0x0B0C #define RK3328_GRF_MACPHY_STATUS 0x0B10 static struct ofw_compat_data compat_data[] = { {"rockchip,rk3288-gmac", 1}, {"rockchip,rk3328-gmac", 1}, {"rockchip,rk3399-gmac", 1}, {NULL, 0} }; #ifdef notyet static void rk3328_set_delays(struct syscon *grf, phandle_t node) { uint32_t tx, rx; if (OF_getencprop(node, "tx_delay", &tx, sizeof(tx)) <= 0) tx = 0x30; if (OF_getencprop(node, "rx_delay", &rx, sizeof(rx)) <= 0) rx = 0x10; tx = ((tx & RK3328_GRF_MAC_CON0_TX_MASK) << RK3328_GRF_MAC_CON0_TX_SHIFT); rx = ((rx & RK3328_GRF_MAC_CON0_TX_MASK) << RK3328_GRF_MAC_CON0_RX_SHIFT); SYSCON_WRITE_4(grf, RK3328_GRF_MAC_CON0, tx | rx | 0xFFFF0000); } #endif #define RK3399_GRF_SOC_CON6 0xc218 #define RK3399_GRF_SOC_CON6_TX_MASK 0x7F #define RK3399_GRF_SOC_CON6_TX_SHIFT 0 #define RK3399_GRF_SOC_CON6_RX_MASK 0x7F #define RK3399_GRF_SOC_CON6_RX_SHIFT 8 #ifdef notyet static void rk3399_set_delays(struct syscon *grf, phandle_t node) { uint32_t tx, rx; if (OF_getencprop(node, "tx_delay", &tx, sizeof(tx)) <= 0) tx = 0x30; if (OF_getencprop(node, "rx_delay", &rx, sizeof(rx)) <= 0) rx = 0x10; tx = ((tx & RK3399_GRF_SOC_CON6_TX_MASK) << RK3399_GRF_SOC_CON6_TX_SHIFT); rx = ((rx & RK3399_GRF_SOC_CON6_TX_MASK) << RK3399_GRF_SOC_CON6_RX_SHIFT); SYSCON_WRITE_4(grf, RK3399_GRF_SOC_CON6, tx | rx | 0xFFFF0000); } #endif static int if_dwc_rk_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Rockchip Gigabit Ethernet Controller"); return (BUS_PROBE_DEFAULT); } static int if_dwc_rk_init(device_t dev) { phandle_t node; struct syscon *grf = NULL; node = ofw_bus_get_node(dev); if (OF_hasprop(node, "rockchip,grf") && syscon_get_by_ofw_property(dev, node, "rockchip,grf", &grf) != 0) { device_printf(dev, "cannot get grf driver handle\n"); return (ENXIO); } #ifdef notyet if (ofw_bus_is_compatible(dev, "rockchip,rk3399-gmac")) rk3399_set_delays(grf, node); else if (ofw_bus_is_compatible(dev, "rockchip,rk3328-gmac")) rk3328_set_delays(grf, node); #endif /* Mode should be set according to dtb property */ return (0); } static int if_dwc_rk_mac_type(device_t dev) { return (DWC_GMAC_ALT_DESC); } static int if_dwc_rk_mii_clk(device_t dev) { /* Should be calculated from the clock */ return (GMAC_MII_CLK_150_250M_DIV102); } static device_method_t if_dwc_rk_methods[] = { DEVMETHOD(device_probe, if_dwc_rk_probe), DEVMETHOD(if_dwc_init, if_dwc_rk_init), DEVMETHOD(if_dwc_mac_type, if_dwc_rk_mac_type), DEVMETHOD(if_dwc_mii_clk, if_dwc_rk_mii_clk), DEVMETHOD_END }; static devclass_t dwc_rk_devclass; extern driver_t dwc_driver; DEFINE_CLASS_1(dwc, dwc_rk_driver, if_dwc_rk_methods, sizeof(struct dwc_softc), dwc_driver); DRIVER_MODULE(dwc_rk, simplebus, dwc_rk_driver, dwc_rk_devclass, 0, 0); MODULE_DEPEND(dwc_rk, dwc, 1, 1, 1); Index: head/sys/arm64/rockchip/rk805.c =================================================================== --- head/sys/arm64/rockchip/rk805.c (revision 355356) +++ head/sys/arm64/rockchip/rk805.c (revision 355357) @@ -1,561 +1,560 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include "regdev_if.h" MALLOC_DEFINE(M_RK805_REG, "RK805 regulator", "RK805 power regulator"); /* #define dprintf(sc, format, arg...) device_printf(sc->base_dev, "%s: " format, __func__, arg) */ #define dprintf(sc, format, arg...) enum rk_pmic_type { RK805 = 1, RK808, }; static struct ofw_compat_data compat_data[] = { {"rockchip,rk805", RK805}, {"rockchip,rk808", RK808}, {NULL, 0} }; struct rk805_regdef { intptr_t id; char *name; uint8_t enable_reg; uint8_t enable_mask; uint8_t voltage_reg; uint8_t voltage_mask; int voltage_min; int voltage_max; int voltage_step; int voltage_nstep; }; struct rk805_reg_sc { struct regnode *regnode; device_t base_dev; struct rk805_regdef *def; phandle_t xref; struct regnode_std_param *param; }; struct rk805_softc { device_t dev; struct mtx mtx; struct resource * res[1]; void * intrcookie; struct intr_config_hook intr_hook; enum rk_pmic_type type; struct rk805_reg_sc **regs; int nregs; }; static struct rk805_regdef rk805_regdefs[] = { { .id = RK805_DCDC1, .name = "DCDC_REG1", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x11, .voltage_reg = RK805_DCDC1_ON_VSEL, .voltage_mask = 0x3F, .voltage_min = 712500, .voltage_max = 1450000, .voltage_step = 12500, .voltage_nstep = 64, }, { .id = RK805_DCDC2, .name = "DCDC_REG2", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x22, .voltage_reg = RK805_DCDC2_ON_VSEL, .voltage_mask = 0x3F, .voltage_min = 712500, .voltage_max = 1450000, .voltage_step = 12500, .voltage_nstep = 64, }, { .id = RK805_DCDC3, .name = "DCDC_REG3", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x44, }, { .id = RK805_DCDC4, .name = "DCDC_REG4", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x88, .voltage_reg = RK805_DCDC4_ON_VSEL, .voltage_mask = 0x3F, .voltage_min = 800000, .voltage_max = 3500000, .voltage_step = 100000, .voltage_nstep = 28, }, { .id = RK805_LDO1, .name = "LDO_REG1", .enable_reg = RK805_LDO_EN, .enable_mask = 0x11, .voltage_reg = RK805_LDO1_ON_VSEL, .voltage_mask = 0x1F, .voltage_min = 800000, .voltage_max = 3400000, .voltage_step = 100000, .voltage_nstep = 27, }, { .id = RK805_LDO2, .name = "LDO_REG2", .enable_reg = RK805_LDO_EN, .enable_mask = 0x22, .voltage_reg = RK805_LDO2_ON_VSEL, .voltage_mask = 0x1F, .voltage_min = 800000, .voltage_max = 3400000, .voltage_step = 100000, .voltage_nstep = 27, }, { .id = RK805_LDO3, .name = "LDO_REG3", .enable_reg = RK805_LDO_EN, .enable_mask = 0x44, .voltage_reg = RK805_LDO3_ON_VSEL, .voltage_mask = 0x1F, .voltage_min = 800000, .voltage_max = 3400000, .voltage_step = 100000, .voltage_nstep = 27, }, }; static struct rk805_regdef rk808_regdefs[] = { { .id = RK805_DCDC1, .name = "DCDC_REG1", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x1, .voltage_reg = RK805_DCDC1_ON_VSEL, .voltage_mask = 0x3F, .voltage_min = 712500, .voltage_max = 1500000, .voltage_step = 12500, .voltage_nstep = 64, }, { .id = RK805_DCDC2, .name = "DCDC_REG2", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x2, .voltage_reg = RK805_DCDC2_ON_VSEL, .voltage_mask = 0x3F, .voltage_min = 712500, .voltage_max = 1500000, .voltage_step = 12500, .voltage_nstep = 64, }, { .id = RK805_DCDC3, .name = "DCDC_REG3", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x4, }, { .id = RK805_DCDC4, .name = "DCDC_REG4", .enable_reg = RK805_DCDC_EN, .enable_mask = 0x8, .voltage_reg = RK805_DCDC4_ON_VSEL, .voltage_mask = 0xF, .voltage_min = 1800000, .voltage_max = 3300000, .voltage_step = 100000, .voltage_nstep = 16, }, }; static int rk805_read(device_t dev, uint8_t reg, uint8_t *data, uint8_t size) { int err; err = iicdev_readfrom(dev, reg, data, size, IIC_INTRWAIT); return (err); } static int rk805_write(device_t dev, uint8_t reg, uint8_t data) { return (iicdev_writeto(dev, reg, &data, 1, IIC_INTRWAIT)); } static int rk805_regnode_init(struct regnode *regnode) { return (0); } static int rk805_regnode_enable(struct regnode *regnode, bool enable, int *udelay) { struct rk805_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); dprintf(sc, "%sabling regulator %s\n", enable ? "En" : "Dis", sc->def->name); rk805_read(sc->base_dev, sc->def->enable_reg, &val, 1); if (enable) val |= sc->def->enable_mask; else val &= ~sc->def->enable_mask; rk805_write(sc->base_dev, sc->def->enable_reg, val); *udelay = 0; return (0); } static void rk805_regnode_reg_to_voltage(struct rk805_reg_sc *sc, uint8_t val, int *uv) { if (val < sc->def->voltage_nstep) *uv = sc->def->voltage_min + val * sc->def->voltage_step; else *uv = sc->def->voltage_min + (sc->def->voltage_nstep * sc->def->voltage_step); } static int rk805_regnode_voltage_to_reg(struct rk805_reg_sc *sc, int min_uvolt, int max_uvolt, uint8_t *val) { uint8_t nval; int nstep, uvolt; nval = 0; uvolt = sc->def->voltage_min; for (nstep = 0; nstep < sc->def->voltage_nstep && uvolt < min_uvolt; nstep++) { ++nval; uvolt += sc->def->voltage_step; } if (uvolt > max_uvolt) return (EINVAL); *val = nval; return (0); } static int rk805_regnode_set_voltage(struct regnode *regnode, int min_uvolt, int max_uvolt, int *udelay) { struct rk805_reg_sc *sc; uint8_t val; int uvolt; sc = regnode_get_softc(regnode); if (!sc->def->voltage_step) return (ENXIO); dprintf(sc, "Setting %s to %d<->%d uvolts\n", sc->def->name, min_uvolt, max_uvolt); rk805_read(sc->base_dev, sc->def->voltage_reg, &val, 1); if (rk805_regnode_voltage_to_reg(sc, min_uvolt, max_uvolt, &val) != 0) return (ERANGE); rk805_write(sc->base_dev, sc->def->voltage_reg, val); rk805_read(sc->base_dev, sc->def->voltage_reg, &val, 1); *udelay = 0; rk805_regnode_reg_to_voltage(sc, val, &uvolt); dprintf(sc, "Regulator %s set to %d uvolt\n", sc->def->name, uvolt); return (0); } static int rk805_regnode_get_voltage(struct regnode *regnode, int *uvolt) { struct rk805_reg_sc *sc; uint8_t val; sc = regnode_get_softc(regnode); if (!sc->def->voltage_step) return (ENXIO); rk805_read(sc->base_dev, sc->def->voltage_reg, &val, 1); rk805_regnode_reg_to_voltage(sc, val & sc->def->voltage_mask, uvolt); dprintf(sc, "Regulator %s is at %d uvolt\n", sc->def->name, *uvolt); return (0); } static regnode_method_t rk805_regnode_methods[] = { /* Regulator interface */ REGNODEMETHOD(regnode_init, rk805_regnode_init), REGNODEMETHOD(regnode_enable, rk805_regnode_enable), REGNODEMETHOD(regnode_set_voltage, rk805_regnode_set_voltage), REGNODEMETHOD(regnode_get_voltage, rk805_regnode_get_voltage), REGNODEMETHOD(regnode_check_voltage, regnode_method_check_voltage), REGNODEMETHOD_END }; DEFINE_CLASS_1(rk805_regnode, rk805_regnode_class, rk805_regnode_methods, sizeof(struct rk805_reg_sc), regnode_class); static struct rk805_reg_sc * rk805_reg_attach(device_t dev, phandle_t node, struct rk805_regdef *def) { struct rk805_reg_sc *reg_sc; struct regnode_init_def initdef; struct regnode *regnode; memset(&initdef, 0, sizeof(initdef)); if (regulator_parse_ofw_stdparam(dev, node, &initdef) != 0) { device_printf(dev, "cannot create regulator\n"); return (NULL); } if (initdef.std_param.min_uvolt == 0) initdef.std_param.min_uvolt = def->voltage_min; if (initdef.std_param.max_uvolt == 0) initdef.std_param.max_uvolt = def->voltage_max; initdef.id = def->id; initdef.ofw_node = node; regnode = regnode_create(dev, &rk805_regnode_class, &initdef); if (regnode == NULL) { device_printf(dev, "cannot create regulator\n"); return (NULL); } reg_sc = regnode_get_softc(regnode); reg_sc->regnode = regnode; reg_sc->base_dev = dev; reg_sc->def = def; reg_sc->xref = OF_xref_from_node(node); reg_sc->param = regnode_get_stdparam(regnode); regnode_register(regnode); return (reg_sc); } static int rk805_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "RockChip RK805 PMIC"); return (BUS_PROBE_DEFAULT); } static void rk805_start(void *pdev) { struct rk805_softc *sc; device_t dev; uint8_t data[2]; int err; dev = pdev; sc = device_get_softc(dev); sc->dev = dev; /* No version register in RK808 */ if (bootverbose && sc->type == RK805) { err = rk805_read(dev, RK805_CHIP_NAME, data, 1); if (err != 0) { device_printf(dev, "Cannot read chip name reg\n"); return; } err = rk805_read(dev, RK805_CHIP_VER, data + 1, 1); if (err != 0) { device_printf(dev, "Cannot read chip version reg\n"); return; } device_printf(dev, "Chip Name: %x\n", data[0] << 4 | ((data[1] >> 4) & 0xf)); device_printf(dev, "Chip Version: %x\n", data[1] & 0xf); } config_intrhook_disestablish(&sc->intr_hook); } static int rk805_attach(device_t dev) { struct rk805_softc *sc; struct rk805_reg_sc *reg; struct rk805_regdef *regdefs; phandle_t rnode, child; int i; sc = device_get_softc(dev); sc->intr_hook.ich_func = rk805_start; sc->intr_hook.ich_arg = dev; if (config_intrhook_establish(&sc->intr_hook) != 0) return (ENOMEM); sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; switch (sc->type) { case RK805: regdefs = rk805_regdefs; sc->nregs = nitems(rk805_regdefs); break; case RK808: regdefs = rk808_regdefs; sc->nregs = nitems(rk808_regdefs); break; default: device_printf(dev, "Unknown type %d\n", sc->type); return (ENXIO); } sc->regs = malloc(sizeof(struct rk805_reg_sc *) * sc->nregs, M_RK805_REG, M_WAITOK | M_ZERO); rnode = ofw_bus_find_child(ofw_bus_get_node(dev), "regulators"); if (rnode > 0) { for (i = 0; i < sc->nregs; i++) { child = ofw_bus_find_child(rnode, regdefs[i].name); if (child == 0) continue; reg = rk805_reg_attach(dev, child, ®defs[i]); if (reg == NULL) { device_printf(dev, "cannot attach regulator %s\n", regdefs[i].name); continue; } sc->regs[i] = reg; if (bootverbose) device_printf(dev, "Regulator %s attached\n", regdefs[i].name); } } return (0); } static int rk805_detach(device_t dev) { /* We cannot detach regulators */ return (EBUSY); } static int rk805_map(device_t dev, phandle_t xref, int ncells, pcell_t *cells, intptr_t *id) { struct rk805_softc *sc; int i; sc = device_get_softc(dev); for (i = 0; i < sc->nregs; i++) { if (sc->regs[i]->xref == xref) { *id = sc->regs[i]->def->id; return (0); } } return (ERANGE); } static device_method_t rk805_methods[] = { DEVMETHOD(device_probe, rk805_probe), DEVMETHOD(device_attach, rk805_attach), DEVMETHOD(device_detach, rk805_detach), /* regdev interface */ DEVMETHOD(regdev_map, rk805_map), DEVMETHOD_END }; static driver_t rk805_driver = { "rk805_pmu", rk805_methods, sizeof(struct rk805_softc), }; static devclass_t rk805_devclass; EARLY_DRIVER_MODULE(rk805, iicbus, rk805_driver, rk805_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST); MODULE_DEPEND(rk805, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); MODULE_VERSION(rk805, 1); Index: head/sys/arm64/rockchip/rk805reg.h =================================================================== --- head/sys/arm64/rockchip/rk805reg.h (revision 355356) +++ head/sys/arm64/rockchip/rk805reg.h (revision 355357) @@ -1,90 +1,89 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _RK805REG_H_ #define _RK805REG_H_ #define RK805_CHIP_NAME 0x17 #define RK805_CHIP_VER 0x18 #define RK805_OTP_VER 0x19 #define RK805_DCDC_EN 0x23 #define RK808_LDO_EN 0x24 #define RK805_SLEEP_DCDC_EN 0x25 #define RK805_SLEEP_LDO_EN 0x26 #define RK805_LDO_EN 0x27 #define RK805_SLEEP_LDO_LP_EN 0x2A #define RK805_DCDC1_CONFIG 0x2E #define RK805_DCDC1_ON_VSEL 0x2F #define RK805_DCDC1_SLEEP_VSEL 0x30 #define RK805_DCDC2_CONFIG 0x32 #define RK805_DCDC2_ON_VSEL 0x33 #define RK805_DCDC2_SLEEP_VSEL 0x34 #define RK805_DCDC3_CONFIG 0x36 #define RK805_DCDC4_CONFIG 0x37 #define RK805_DCDC4_ON_VSEL 0x38 #define RK805_DCDC4_SLEEP_VSEL 0x39 #define RK805_LDO1_ON_VSEL 0x3B #define RK805_LDO1_SLEEP_VSEL 0x3C #define RK805_LDO2_ON_VSEL 0x3D #define RK805_LDO2_SLEEP_VSEL 0x3E #define RK805_LDO3_ON_VSEL 0x3F #define RK805_LDO3_SLEEP_VSEL 0x40 enum rk805_regulator { RK805_DCDC1 = 0, RK805_DCDC2, RK805_DCDC3, RK805_DCDC4, RK805_LDO1, RK805_LDO2, RK805_LDO3, }; enum rk808_regulator { RK808_DCDC1 = 0, RK808_DCDC2, RK808_DCDC3, RK808_DCDC4, RK808_LDO1, RK808_LDO2, RK808_LDO3, RK808_LDO4, RK808_LDO5, RK808_LDO6, RK808_LDO7, RK808_LDO8, RK808_SWITCH1, RK808_SWITCH2, }; #endif /* _RK805REG_H_ */ Index: head/sys/arm64/rockchip/rk_gpio.c =================================================================== --- head/sys/arm64/rockchip/rk_gpio.c (revision 355356) +++ head/sys/arm64/rockchip/rk_gpio.c (revision 355357) @@ -1,447 +1,446 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gpio_if.h" #define RK_GPIO_SWPORTA_DR 0x00 /* Data register */ #define RK_GPIO_SWPORTA_DDR 0x04 /* Data direction register */ #define RK_GPIO_INTEN 0x30 /* Interrupt enable register */ #define RK_GPIO_INTMASK 0x34 /* Interrupt mask register */ #define RK_GPIO_INTTYPE_LEVEL 0x38 /* Interrupt level register */ #define RK_GPIO_INT_POLARITY 0x3C /* Interrupt polarity register */ #define RK_GPIO_INT_STATUS 0x40 /* Interrupt status register */ #define RK_GPIO_INT_RAWSTATUS 0x44 /* Raw Interrupt status register */ #define RK_GPIO_DEBOUNCE 0x48 /* Debounce enable register */ #define RK_GPIO_PORTA_EOI 0x4C /* Clear interrupt register */ #define RK_GPIO_EXT_PORTA 0x50 /* External port register */ #define RK_GPIO_LS_SYNC 0x60 /* Level sensitive syncronization enable register */ struct rk_gpio_softc { device_t sc_dev; device_t sc_busdev; struct mtx sc_mtx; struct resource *sc_res[2]; bus_space_tag_t sc_bst; bus_space_handle_t sc_bsh; clk_t clk; }; static struct ofw_compat_data compat_data[] = { {"rockchip,gpio-bank", 1}, {NULL, 0} }; static struct resource_spec rk_gpio_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_IRQ, 0, RF_ACTIVE }, { -1, 0 } }; static int rk_gpio_detach(device_t dev); #define RK_GPIO_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx) #define RK_GPIO_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx) #define RK_GPIO_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) #define RK_GPIO_WRITE(_sc, _off, _val) \ bus_space_write_4(_sc->sc_bst, _sc->sc_bsh, _off, _val) #define RK_GPIO_READ(_sc, _off) \ bus_space_read_4(_sc->sc_bst, _sc->sc_bsh, _off) static int rk_gpio_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "RockChip GPIO Bank controller"); return (BUS_PROBE_DEFAULT); } static int rk_gpio_attach(device_t dev) { struct rk_gpio_softc *sc; phandle_t node; int err; sc = device_get_softc(dev); sc->sc_dev = dev; node = ofw_bus_get_node(sc->sc_dev); if (!OF_hasprop(node, "gpio-controller")) return (ENXIO); mtx_init(&sc->sc_mtx, "rk gpio", "gpio", MTX_SPIN); if (bus_alloc_resources(dev, rk_gpio_spec, sc->sc_res)) { device_printf(dev, "could not allocate resources\n"); bus_release_resources(dev, rk_gpio_spec, sc->sc_res); mtx_destroy(&sc->sc_mtx); return (ENXIO); } sc->sc_bst = rman_get_bustag(sc->sc_res[0]); sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]); if (clk_get_by_ofw_index(dev, 0, 0, &sc->clk) != 0) { device_printf(dev, "Cannot get clock\n"); rk_gpio_detach(dev); return (ENXIO); } err = clk_enable(sc->clk); if (err != 0) { device_printf(dev, "Could not enable clock %s\n", clk_get_name(sc->clk)); rk_gpio_detach(dev); return (ENXIO); } sc->sc_busdev = gpiobus_attach_bus(dev); if (sc->sc_busdev == NULL) { rk_gpio_detach(dev); return (ENXIO); } return (0); } static int rk_gpio_detach(device_t dev) { struct rk_gpio_softc *sc; sc = device_get_softc(dev); if (sc->sc_busdev) gpiobus_detach_bus(dev); bus_release_resources(dev, rk_gpio_spec, sc->sc_res); mtx_destroy(&sc->sc_mtx); clk_disable(sc->clk); return(0); } static device_t rk_gpio_get_bus(device_t dev) { struct rk_gpio_softc *sc; sc = device_get_softc(dev); return (sc->sc_busdev); } static int rk_gpio_pin_max(device_t dev, int *maxpin) { /* Each bank have always 32 pins */ /* XXX not true*/ *maxpin = 32; return (0); } static int rk_gpio_pin_getname(device_t dev, uint32_t pin, char *name) { struct rk_gpio_softc *sc; sc = device_get_softc(dev); if (pin >= 32) return (EINVAL); RK_GPIO_LOCK(sc); snprintf(name, GPIOMAXNAME, "gpio%d", pin); RK_GPIO_UNLOCK(sc); return (0); } static int rk_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) { struct rk_gpio_softc *sc; uint32_t reg; sc = device_get_softc(dev); /* XXX Combine this with parent (pinctrl) */ RK_GPIO_LOCK(sc); reg = RK_GPIO_READ(sc, RK_GPIO_SWPORTA_DDR); RK_GPIO_UNLOCK(sc); if (reg & (1 << pin)) *flags = GPIO_PIN_OUTPUT; else *flags = GPIO_PIN_INPUT; return (0); } static int rk_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) { /* Caps are managed by the pinctrl device */ /* XXX Pass this to parent (pinctrl) */ *caps = 0; return (0); } static int rk_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) { struct rk_gpio_softc *sc; uint32_t reg; sc = device_get_softc(dev); /* XXX Combine this with parent (pinctrl) */ RK_GPIO_LOCK(sc); reg = RK_GPIO_READ(sc, RK_GPIO_SWPORTA_DDR); if (flags & GPIO_PIN_INPUT) reg &= ~(1 << pin); else if (flags & GPIO_PIN_OUTPUT) reg |= (1 << pin); RK_GPIO_WRITE(sc, RK_GPIO_SWPORTA_DDR, reg); RK_GPIO_UNLOCK(sc); return (0); } static int rk_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) { struct rk_gpio_softc *sc; uint32_t reg; sc = device_get_softc(dev); RK_GPIO_LOCK(sc); reg = RK_GPIO_READ(sc, RK_GPIO_EXT_PORTA); RK_GPIO_UNLOCK(sc); *val = reg & (1 << pin) ? 1 : 0; return (0); } static int rk_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) { struct rk_gpio_softc *sc; uint32_t reg; sc = device_get_softc(dev); RK_GPIO_LOCK(sc); reg = RK_GPIO_READ(sc, RK_GPIO_SWPORTA_DR); if (value) reg |= (1 << pin); else reg &= ~(1 << pin); RK_GPIO_WRITE(sc, RK_GPIO_SWPORTA_DR, reg); RK_GPIO_UNLOCK(sc); return (0); } static int rk_gpio_pin_toggle(device_t dev, uint32_t pin) { struct rk_gpio_softc *sc; uint32_t reg; sc = device_get_softc(dev); RK_GPIO_LOCK(sc); reg = RK_GPIO_READ(sc, RK_GPIO_SWPORTA_DR); if (reg & (1 << pin)) reg &= ~(1 << pin); else reg |= (1 << pin); RK_GPIO_WRITE(sc, RK_GPIO_SWPORTA_DR, reg); RK_GPIO_UNLOCK(sc); return (0); } static int rk_gpio_pin_access_32(device_t dev, uint32_t first_pin, uint32_t clear_pins, uint32_t change_pins, uint32_t *orig_pins) { struct rk_gpio_softc *sc; uint32_t reg; sc = device_get_softc(dev); RK_GPIO_LOCK(sc); reg = RK_GPIO_READ(sc, RK_GPIO_SWPORTA_DR); if (orig_pins) *orig_pins = reg; if ((clear_pins | change_pins) != 0) { reg = (reg & ~clear_pins) ^ change_pins; RK_GPIO_WRITE(sc, RK_GPIO_SWPORTA_DR, reg); } RK_GPIO_UNLOCK(sc); return (0); } static int rk_gpio_pin_config_32(device_t dev, uint32_t first_pin, uint32_t num_pins, uint32_t *pin_flags) { struct rk_gpio_softc *sc; uint32_t reg, set, mask, flags; int i; sc = device_get_softc(dev); if (first_pin != 0 || num_pins > 32) return (EINVAL); set = 0; mask = 0; for (i = 0; i < num_pins; i++) { mask = (mask << 1) | 1; flags = pin_flags[i]; if (flags & GPIO_PIN_INPUT) { set &= ~(1 << i); } else if (flags & GPIO_PIN_OUTPUT) { set |= (1 << i); } } RK_GPIO_LOCK(sc); reg = RK_GPIO_READ(sc, RK_GPIO_SWPORTA_DDR); reg &= ~mask; reg |= set; RK_GPIO_WRITE(sc, RK_GPIO_SWPORTA_DDR, reg); RK_GPIO_UNLOCK(sc); return (0); } static int rk_gpio_map_gpios(device_t bus, phandle_t dev, phandle_t gparent, int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags) { /* The gpios are mapped as */ *pin = gpios[0]; *flags = gpios[1]; return (0); } static phandle_t rk_gpio_get_node(device_t bus, device_t dev) { /* We only have one child, the GPIO bus, which needs our own node. */ return (ofw_bus_get_node(bus)); } static device_method_t rk_gpio_methods[] = { /* Device interface */ DEVMETHOD(device_probe, rk_gpio_probe), DEVMETHOD(device_attach, rk_gpio_attach), DEVMETHOD(device_detach, rk_gpio_detach), /* GPIO protocol */ DEVMETHOD(gpio_get_bus, rk_gpio_get_bus), DEVMETHOD(gpio_pin_max, rk_gpio_pin_max), DEVMETHOD(gpio_pin_getname, rk_gpio_pin_getname), DEVMETHOD(gpio_pin_getflags, rk_gpio_pin_getflags), DEVMETHOD(gpio_pin_getcaps, rk_gpio_pin_getcaps), DEVMETHOD(gpio_pin_setflags, rk_gpio_pin_setflags), DEVMETHOD(gpio_pin_get, rk_gpio_pin_get), DEVMETHOD(gpio_pin_set, rk_gpio_pin_set), DEVMETHOD(gpio_pin_toggle, rk_gpio_pin_toggle), DEVMETHOD(gpio_pin_access_32, rk_gpio_pin_access_32), DEVMETHOD(gpio_pin_config_32, rk_gpio_pin_config_32), DEVMETHOD(gpio_map_gpios, rk_gpio_map_gpios), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_node, rk_gpio_get_node), DEVMETHOD_END }; static driver_t rk_gpio_driver = { "gpio", rk_gpio_methods, sizeof(struct rk_gpio_softc), }; static devclass_t rk_gpio_devclass; /* * GPIO driver is always a child of rk_pinctrl driver and should be probed * and attached within rk_pinctrl_attach function. Due to this, bus pass order * must be same as bus pass order of rk_pinctrl driver. */ EARLY_DRIVER_MODULE(rk_gpio, simplebus, rk_gpio_driver, rk_gpio_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); Index: head/sys/arm64/rockchip/rk_grf.c =================================================================== --- head/sys/arm64/rockchip/rk_grf.c (revision 355356) +++ head/sys/arm64/rockchip/rk_grf.c (revision 355357) @@ -1,80 +1,79 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include static struct ofw_compat_data compat_data[] = { {"rockchip,rk3288-grf", 1}, {"rockchip,rk3328-grf", 1}, {"rockchip,rk3399-grf", 1}, {"rockchip,rk3399-pmugrf", 1}, {NULL, 0} }; static int rk_grf_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "RockChip General Register Files"); return (BUS_PROBE_DEFAULT); } static device_method_t rk_grf_methods[] = { DEVMETHOD(device_probe, rk_grf_probe), DEVMETHOD_END }; DEFINE_CLASS_1(rk_grf, rk_grf_driver, rk_grf_methods, sizeof(struct simple_mfd_softc), simple_mfd_driver); static devclass_t rk_grf_devclass; EARLY_DRIVER_MODULE(rk_grf, simplebus, rk_grf_driver, rk_grf_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); MODULE_VERSION(rk_grf, 1); Index: head/sys/arm64/rockchip/rk_pinctrl.c =================================================================== --- head/sys/arm64/rockchip/rk_pinctrl.c (revision 355356) +++ head/sys/arm64/rockchip/rk_pinctrl.c (revision 355357) @@ -1,1040 +1,1039 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gpio_if.h" #include "syscon_if.h" struct rk_pinctrl_pin_drive { uint32_t bank; uint32_t subbank; uint32_t offset; uint32_t value; uint32_t ma; }; struct rk_pinctrl_bank { uint32_t bank; uint32_t subbank; uint32_t offset; uint32_t nbits; }; struct rk_pinctrl_pin_fixup { uint32_t bank; uint32_t subbank; uint32_t pin; uint32_t reg; uint32_t bit; uint32_t mask; }; struct rk_pinctrl_gpio { uint32_t bank; char *gpio_name; device_t gpio_dev; }; struct rk_pinctrl_softc; struct rk_pinctrl_conf { struct rk_pinctrl_bank *iomux_conf; uint32_t iomux_nbanks; struct rk_pinctrl_pin_fixup *pin_fixup; uint32_t npin_fixup; struct rk_pinctrl_pin_drive *pin_drive; uint32_t npin_drive; struct rk_pinctrl_gpio *gpio_bank; uint32_t ngpio_bank; uint32_t (*get_pd_offset)(struct rk_pinctrl_softc *, uint32_t); struct syscon *(*get_syscon)(struct rk_pinctrl_softc *, uint32_t); }; struct rk_pinctrl_softc { struct simplebus_softc simplebus_sc; device_t dev; struct syscon *grf; struct syscon *pmu; struct rk_pinctrl_conf *conf; }; #define RK_IOMUX(_bank, _subbank, _offset, _nbits) \ { \ .bank = _bank, \ .subbank = _subbank, \ .offset = _offset, \ .nbits = _nbits, \ } #define RK_PINFIX(_bank, _pin, _reg, _bit, _mask) \ { \ .bank = _bank, \ .pin = _pin, \ .reg = _reg, \ .bit = _bit, \ .mask = _mask, \ } #define RK_PINDRIVE(_bank, _subbank, _offset, _value, _ma) \ { \ .bank = _bank, \ .subbank = _subbank, \ .offset = _offset, \ .value = _value, \ .ma = _ma, \ } #define RK_GPIO(_bank, _name) \ { \ .bank = _bank, \ .gpio_name = _name, \ } static struct rk_pinctrl_gpio rk3288_gpio_bank[] = { RK_GPIO(0, "gpio0"), RK_GPIO(1, "gpio1"), RK_GPIO(2, "gpio2"), RK_GPIO(3, "gpio3"), RK_GPIO(4, "gpio4"), RK_GPIO(5, "gpio5"), RK_GPIO(6, "gpio6"), RK_GPIO(7, "gpio7"), RK_GPIO(8, "gpio8"), }; static struct rk_pinctrl_bank rk3288_iomux_bank[] = { /* bank sub offs nbits */ /* PMU */ RK_IOMUX(0, 0, 0x0084, 2), RK_IOMUX(0, 1, 0x0088, 2), RK_IOMUX(0, 2, 0x008C, 2), /* GFR */ RK_IOMUX(1, 3, 0x000C, 2), RK_IOMUX(2, 0, 0x0010, 2), RK_IOMUX(2, 1, 0x0014, 2), RK_IOMUX(2, 2, 0x0018, 2), RK_IOMUX(2, 3, 0x001C, 2), RK_IOMUX(3, 0, 0x0020, 2), RK_IOMUX(3, 1, 0x0024, 2), RK_IOMUX(3, 2, 0x0028, 2), RK_IOMUX(3, 3, 0x002C, 4), RK_IOMUX(4, 0, 0x0034, 4), RK_IOMUX(4, 1, 0x003C, 4), RK_IOMUX(4, 2, 0x0044, 2), RK_IOMUX(4, 3, 0x0048, 2), /* 5,0 - Empty */ RK_IOMUX(5, 1, 0x0050, 2), RK_IOMUX(5, 2, 0x0054, 2), /* 5,3 - Empty */ RK_IOMUX(6, 0, 0x005C, 2), RK_IOMUX(6, 1, 0x0060, 2), RK_IOMUX(6, 2, 0x0064, 2), /* 6,3 - Empty */ RK_IOMUX(7, 0, 0x006C, 2), RK_IOMUX(7, 1, 0x0070, 2), RK_IOMUX(7, 2, 0x0074, 4), /* 7,3 - Empty */ RK_IOMUX(8, 0, 0x0080, 2), RK_IOMUX(8, 1, 0x0084, 2), /* 8,2 - Empty */ /* 8,3 - Empty */ }; static struct rk_pinctrl_pin_fixup rk3288_pin_fixup[] = { }; static struct rk_pinctrl_pin_drive rk3288_pin_drive[] = { /* bank sub offs val ma */ /* GPIO0A (PMU)*/ RK_PINDRIVE(0, 0, 0x070, 0, 2), RK_PINDRIVE(0, 0, 0x070, 1, 4), RK_PINDRIVE(0, 0, 0x070, 2, 8), RK_PINDRIVE(0, 0, 0x070, 3, 12), /* GPIO0B (PMU)*/ RK_PINDRIVE(0, 1, 0x074, 0, 2), RK_PINDRIVE(0, 1, 0x074, 1, 4), RK_PINDRIVE(0, 1, 0x074, 2, 8), RK_PINDRIVE(0, 1, 0x074, 3, 12), /* GPIO0C (PMU)*/ RK_PINDRIVE(0, 2, 0x078, 0, 2), RK_PINDRIVE(0, 2, 0x078, 1, 4), RK_PINDRIVE(0, 2, 0x078, 2, 8), RK_PINDRIVE(0, 2, 0x078, 3, 12), /* GPIO1D */ RK_PINDRIVE(1, 3, 0x1CC, 0, 2), RK_PINDRIVE(1, 3, 0x1CC, 1, 4), RK_PINDRIVE(1, 3, 0x1CC, 2, 8), RK_PINDRIVE(1, 3, 0x1CC, 3, 12), /* GPIO2A */ RK_PINDRIVE(2, 0, 0x1D0, 0, 2), RK_PINDRIVE(2, 0, 0x1D0, 1, 4), RK_PINDRIVE(2, 0, 0x1D0, 2, 8), RK_PINDRIVE(2, 0, 0x1D0, 3, 12), /* GPIO2B */ RK_PINDRIVE(2, 1, 0x1D4, 0, 2), RK_PINDRIVE(2, 1, 0x1D4, 1, 4), RK_PINDRIVE(2, 1, 0x1D4, 2, 8), RK_PINDRIVE(2, 1, 0x1D4, 3, 12), /* GPIO2C */ RK_PINDRIVE(2, 2, 0x1D8, 0, 2), RK_PINDRIVE(2, 2, 0x1D8, 1, 4), RK_PINDRIVE(2, 2, 0x1D8, 2, 8), RK_PINDRIVE(2, 2, 0x1D8, 3, 12), /* GPIO2D */ RK_PINDRIVE(2, 3, 0x1DC, 0, 2), RK_PINDRIVE(2, 3, 0x1DC, 1, 4), RK_PINDRIVE(2, 3, 0x1DC, 2, 8), RK_PINDRIVE(2, 3, 0x1DC, 3, 12), /* GPIO3A */ RK_PINDRIVE(3, 0, 0x1E0, 0, 2), RK_PINDRIVE(3, 0, 0x1E0, 1, 4), RK_PINDRIVE(3, 0, 0x1E0, 2, 8), RK_PINDRIVE(3, 0, 0x1E0, 3, 12), /* GPIO3B */ RK_PINDRIVE(3, 1, 0x1E4, 0, 2), RK_PINDRIVE(3, 1, 0x1E4, 1, 4), RK_PINDRIVE(3, 1, 0x1E4, 2, 8), RK_PINDRIVE(3, 1, 0x1E4, 3, 12), /* GPIO3C */ RK_PINDRIVE(3, 2, 0x1E8, 0, 2), RK_PINDRIVE(3, 2, 0x1E8, 1, 4), RK_PINDRIVE(3, 2, 0x1E8, 2, 8), RK_PINDRIVE(3, 2, 0x1E8, 3, 12), /* GPIO3D */ RK_PINDRIVE(3, 3, 0x1EC, 0, 2), RK_PINDRIVE(3, 3, 0x1EC, 1, 4), RK_PINDRIVE(3, 3, 0x1EC, 2, 8), RK_PINDRIVE(3, 3, 0x1EC, 3, 12), /* GPIO4A */ RK_PINDRIVE(4, 0, 0x1F0, 0, 2), RK_PINDRIVE(4, 0, 0x1F0, 1, 4), RK_PINDRIVE(4, 0, 0x1F0, 2, 8), RK_PINDRIVE(4, 0, 0x1F0, 3, 12), /* GPIO4B */ RK_PINDRIVE(4, 1, 0x1F4, 0, 2), RK_PINDRIVE(4, 1, 0x1F4, 1, 4), RK_PINDRIVE(4, 1, 0x1F4, 2, 8), RK_PINDRIVE(4, 1, 0x1F4, 3, 12), /* GPIO4C */ RK_PINDRIVE(4, 2, 0x1F8, 0, 2), RK_PINDRIVE(4, 2, 0x1F8, 1, 4), RK_PINDRIVE(4, 2, 0x1F8, 2, 8), RK_PINDRIVE(4, 2, 0x1F8, 3, 12), /* GPIO4D */ RK_PINDRIVE(4, 3, 0x1FC, 0, 2), RK_PINDRIVE(4, 3, 0x1FC, 1, 4), RK_PINDRIVE(4, 3, 0x1FC, 2, 8), RK_PINDRIVE(4, 3, 0x1FC, 3, 12), /* GPIO5B */ RK_PINDRIVE(5, 1, 0x204, 0, 2), RK_PINDRIVE(5, 1, 0x204, 1, 4), RK_PINDRIVE(5, 1, 0x204, 2, 8), RK_PINDRIVE(5, 1, 0x204, 3, 12), /* GPIO5C */ RK_PINDRIVE(5, 2, 0x208, 0, 2), RK_PINDRIVE(5, 2, 0x208, 1, 4), RK_PINDRIVE(5, 2, 0x208, 2, 8), RK_PINDRIVE(5, 2, 0x208, 3, 12), /* GPIO6A */ RK_PINDRIVE(6, 0, 0x210, 0, 2), RK_PINDRIVE(6, 0, 0x210, 1, 4), RK_PINDRIVE(6, 0, 0x210, 2, 8), RK_PINDRIVE(6, 0, 0x210, 3, 12), /* GPIO6B */ RK_PINDRIVE(6, 1, 0x214, 0, 2), RK_PINDRIVE(6, 1, 0x214, 1, 4), RK_PINDRIVE(6, 1, 0x214, 2, 8), RK_PINDRIVE(6, 1, 0x214, 3, 12), /* GPIO6C */ RK_PINDRIVE(6, 2, 0x218, 0, 2), RK_PINDRIVE(6, 2, 0x218, 1, 4), RK_PINDRIVE(6, 2, 0x218, 2, 8), RK_PINDRIVE(6, 2, 0x218, 3, 12), /* GPIO7A */ RK_PINDRIVE(7, 0, 0x220, 0, 2), RK_PINDRIVE(7, 0, 0x220, 1, 4), RK_PINDRIVE(7, 0, 0x220, 2, 8), RK_PINDRIVE(7, 0, 0x220, 3, 12), /* GPIO7B */ RK_PINDRIVE(7, 1, 0x224, 0, 2), RK_PINDRIVE(7, 1, 0x224, 1, 4), RK_PINDRIVE(7, 1, 0x224, 2, 8), RK_PINDRIVE(7, 1, 0x224, 3, 12), /* GPIO7C */ RK_PINDRIVE(7, 2, 0x228, 0, 2), RK_PINDRIVE(7, 2, 0x228, 1, 4), RK_PINDRIVE(7, 2, 0x228, 2, 8), RK_PINDRIVE(7, 2, 0x228, 3, 12), /* GPIO8A */ RK_PINDRIVE(8, 0, 0x230, 0, 2), RK_PINDRIVE(8, 0, 0x230, 1, 4), RK_PINDRIVE(8, 0, 0x230, 2, 8), RK_PINDRIVE(8, 0, 0x230, 3, 12), /* GPIO8B */ RK_PINDRIVE(8, 1, 0x234, 0, 2), RK_PINDRIVE(8, 1, 0x234, 1, 4), RK_PINDRIVE(8, 1, 0x234, 2, 8), RK_PINDRIVE(8, 1, 0x234, 3, 12), }; static uint32_t rk3288_get_pd_offset(struct rk_pinctrl_softc *sc, uint32_t bank) { if (bank == 0) return (0x064); /* PMU */ return (0x130); } static struct syscon * rk3288_get_syscon(struct rk_pinctrl_softc *sc, uint32_t bank) { if (bank == 0) return (sc->pmu); return (sc->grf); } struct rk_pinctrl_conf rk3288_conf = { .iomux_conf = rk3288_iomux_bank, .iomux_nbanks = nitems(rk3288_iomux_bank), .pin_fixup = rk3288_pin_fixup, .npin_fixup = nitems(rk3288_pin_fixup), .pin_drive = rk3288_pin_drive, .npin_drive = nitems(rk3288_pin_drive), .gpio_bank = rk3288_gpio_bank, .ngpio_bank = nitems(rk3288_gpio_bank), .get_pd_offset = rk3288_get_pd_offset, .get_syscon = rk3288_get_syscon, }; static struct rk_pinctrl_gpio rk3328_gpio_bank[] = { RK_GPIO(0, "gpio0"), RK_GPIO(1, "gpio1"), RK_GPIO(2, "gpio2"), RK_GPIO(3, "gpio3"), }; static struct rk_pinctrl_bank rk3328_iomux_bank[] = { /* bank sub offs nbits */ RK_IOMUX(0, 0, 0x0000, 2), RK_IOMUX(0, 1, 0x0004, 2), RK_IOMUX(0, 2, 0x0008, 2), RK_IOMUX(0, 3, 0x000C, 2), RK_IOMUX(1, 0, 0x0010, 2), RK_IOMUX(1, 1, 0x0014, 2), RK_IOMUX(1, 2, 0x0018, 2), RK_IOMUX(1, 3, 0x001C, 2), RK_IOMUX(2, 0, 0x0020, 2), RK_IOMUX(2, 1, 0x0024, 3), RK_IOMUX(2, 2, 0x002c, 3), RK_IOMUX(2, 3, 0x0034, 2), RK_IOMUX(3, 0, 0x0038, 3), RK_IOMUX(3, 1, 0x0040, 3), RK_IOMUX(3, 2, 0x0048, 2), RK_IOMUX(3, 3, 0x004c, 2), }; static struct rk_pinctrl_pin_fixup rk3328_pin_fixup[] = { /* bank pin reg bit mask */ RK_PINFIX(2, 12, 0x24, 8, 0x300), RK_PINFIX(2, 15, 0x28, 0, 0x7), RK_PINFIX(2, 23, 0x30, 14, 0x6000), }; static struct rk_pinctrl_pin_drive rk3328_pin_drive[] = { /* bank sub offs val ma */ RK_PINDRIVE(0, 0, 0x200, 0, 2), RK_PINDRIVE(0, 0, 0x200, 1, 4), RK_PINDRIVE(0, 0, 0x200, 2, 8), RK_PINDRIVE(0, 0, 0x200, 3, 12), RK_PINDRIVE(0, 1, 0x204, 0, 2), RK_PINDRIVE(0, 1, 0x204, 1, 4), RK_PINDRIVE(0, 1, 0x204, 2, 8), RK_PINDRIVE(0, 1, 0x204, 3, 12), RK_PINDRIVE(0, 2, 0x208, 0, 2), RK_PINDRIVE(0, 2, 0x208, 1, 4), RK_PINDRIVE(0, 2, 0x208, 2, 8), RK_PINDRIVE(0, 2, 0x208, 3, 12), RK_PINDRIVE(0, 3, 0x20C, 0, 2), RK_PINDRIVE(0, 3, 0x20C, 1, 4), RK_PINDRIVE(0, 3, 0x20C, 2, 8), RK_PINDRIVE(0, 3, 0x20C, 3, 12), RK_PINDRIVE(1, 0, 0x210, 0, 2), RK_PINDRIVE(1, 0, 0x210, 1, 4), RK_PINDRIVE(1, 0, 0x210, 2, 8), RK_PINDRIVE(1, 0, 0x210, 3, 12), RK_PINDRIVE(1, 1, 0x214, 0, 2), RK_PINDRIVE(1, 1, 0x214, 1, 4), RK_PINDRIVE(1, 1, 0x214, 2, 8), RK_PINDRIVE(1, 1, 0x214, 3, 12), RK_PINDRIVE(1, 2, 0x218, 0, 2), RK_PINDRIVE(1, 2, 0x218, 1, 4), RK_PINDRIVE(1, 2, 0x218, 2, 8), RK_PINDRIVE(1, 2, 0x218, 3, 12), RK_PINDRIVE(1, 3, 0x21C, 0, 2), RK_PINDRIVE(1, 3, 0x21C, 1, 4), RK_PINDRIVE(1, 3, 0x21C, 2, 8), RK_PINDRIVE(1, 3, 0x21C, 3, 12), RK_PINDRIVE(2, 0, 0x220, 0, 2), RK_PINDRIVE(2, 0, 0x220, 1, 4), RK_PINDRIVE(2, 0, 0x220, 2, 8), RK_PINDRIVE(2, 0, 0x220, 3, 12), RK_PINDRIVE(2, 1, 0x224, 0, 2), RK_PINDRIVE(2, 1, 0x224, 1, 4), RK_PINDRIVE(2, 1, 0x224, 2, 8), RK_PINDRIVE(2, 1, 0x224, 3, 12), RK_PINDRIVE(2, 2, 0x228, 0, 2), RK_PINDRIVE(2, 2, 0x228, 1, 4), RK_PINDRIVE(2, 2, 0x228, 2, 8), RK_PINDRIVE(2, 2, 0x228, 3, 12), RK_PINDRIVE(2, 3, 0x22C, 0, 2), RK_PINDRIVE(2, 3, 0x22C, 1, 4), RK_PINDRIVE(2, 3, 0x22C, 2, 8), RK_PINDRIVE(2, 3, 0x22C, 3, 12), RK_PINDRIVE(3, 0, 0x230, 0, 2), RK_PINDRIVE(3, 0, 0x230, 1, 4), RK_PINDRIVE(3, 0, 0x230, 2, 8), RK_PINDRIVE(3, 0, 0x230, 3, 12), RK_PINDRIVE(3, 1, 0x234, 0, 2), RK_PINDRIVE(3, 1, 0x234, 1, 4), RK_PINDRIVE(3, 1, 0x234, 2, 8), RK_PINDRIVE(3, 1, 0x234, 3, 12), RK_PINDRIVE(3, 2, 0x238, 0, 2), RK_PINDRIVE(3, 2, 0x238, 1, 4), RK_PINDRIVE(3, 2, 0x238, 2, 8), RK_PINDRIVE(3, 2, 0x238, 3, 12), RK_PINDRIVE(3, 3, 0x23C, 0, 2), RK_PINDRIVE(3, 3, 0x23C, 1, 4), RK_PINDRIVE(3, 3, 0x23C, 2, 8), RK_PINDRIVE(3, 3, 0x23C, 3, 12), }; static uint32_t rk3328_get_pd_offset(struct rk_pinctrl_softc *sc, uint32_t bank) { return (0x100); } static struct syscon * rk3328_get_syscon(struct rk_pinctrl_softc *sc, uint32_t bank) { return (sc->grf); } struct rk_pinctrl_conf rk3328_conf = { .iomux_conf = rk3328_iomux_bank, .iomux_nbanks = nitems(rk3328_iomux_bank), .pin_fixup = rk3328_pin_fixup, .npin_fixup = nitems(rk3328_pin_fixup), .pin_drive = rk3328_pin_drive, .npin_drive = nitems(rk3328_pin_drive), .gpio_bank = rk3328_gpio_bank, .ngpio_bank = nitems(rk3328_gpio_bank), .get_pd_offset = rk3328_get_pd_offset, .get_syscon = rk3328_get_syscon, }; static struct rk_pinctrl_gpio rk3399_gpio_bank[] = { RK_GPIO(0, "gpio0"), RK_GPIO(1, "gpio1"), RK_GPIO(2, "gpio2"), RK_GPIO(3, "gpio3"), RK_GPIO(4, "gpio4"), }; static struct rk_pinctrl_bank rk3399_iomux_bank[] = { /* bank sub offs nbits */ RK_IOMUX(0, 0, 0x0000, 2), RK_IOMUX(0, 1, 0x0004, 2), RK_IOMUX(0, 2, 0x0008, 2), RK_IOMUX(0, 3, 0x000C, 2), RK_IOMUX(1, 0, 0x0010, 2), RK_IOMUX(1, 1, 0x0014, 2), RK_IOMUX(1, 2, 0x0018, 2), RK_IOMUX(1, 3, 0x001C, 2), RK_IOMUX(2, 0, 0xE000, 2), RK_IOMUX(2, 1, 0xE004, 2), RK_IOMUX(2, 2, 0xE008, 2), RK_IOMUX(2, 3, 0xE00C, 2), RK_IOMUX(3, 0, 0xE010, 2), RK_IOMUX(3, 1, 0xE014, 2), RK_IOMUX(3, 2, 0xE018, 2), RK_IOMUX(3, 3, 0xE01C, 2), RK_IOMUX(4, 0, 0xE020, 2), RK_IOMUX(4, 1, 0xE024, 2), RK_IOMUX(4, 2, 0xE028, 2), RK_IOMUX(4, 3, 0xE02C, 2), }; static struct rk_pinctrl_pin_fixup rk3399_pin_fixup[] = {}; static struct rk_pinctrl_pin_drive rk3399_pin_drive[] = { /* bank sub offs val ma */ /* GPIO0A */ RK_PINDRIVE(0, 0, 0x80, 0, 5), RK_PINDRIVE(0, 0, 0x80, 1, 10), RK_PINDRIVE(0, 0, 0x80, 2, 15), RK_PINDRIVE(0, 0, 0x80, 3, 20), /* GPIOB */ RK_PINDRIVE(0, 1, 0x88, 0, 5), RK_PINDRIVE(0, 1, 0x88, 1, 10), RK_PINDRIVE(0, 1, 0x88, 2, 15), RK_PINDRIVE(0, 1, 0x88, 3, 20), /* GPIO1A */ RK_PINDRIVE(1, 0, 0xA0, 0, 3), RK_PINDRIVE(1, 0, 0xA0, 1, 6), RK_PINDRIVE(1, 0, 0xA0, 2, 9), RK_PINDRIVE(1, 0, 0xA0, 3, 12), /* GPIO1B */ RK_PINDRIVE(1, 1, 0xA8, 0, 3), RK_PINDRIVE(1, 1, 0xA8, 1, 6), RK_PINDRIVE(1, 1, 0xA8, 2, 9), RK_PINDRIVE(1, 1, 0xA8, 3, 12), /* GPIO1C */ RK_PINDRIVE(1, 2, 0xB0, 0, 3), RK_PINDRIVE(1, 2, 0xB0, 1, 6), RK_PINDRIVE(1, 2, 0xB0, 2, 9), RK_PINDRIVE(1, 2, 0xB0, 3, 12), /* GPIO1D */ RK_PINDRIVE(1, 3, 0xB8, 0, 3), RK_PINDRIVE(1, 3, 0xB8, 1, 6), RK_PINDRIVE(1, 3, 0xB8, 2, 9), RK_PINDRIVE(1, 3, 0xB8, 3, 12), }; static uint32_t rk3399_get_pd_offset(struct rk_pinctrl_softc *sc, uint32_t bank) { if (bank < 2) return (0x40); return (0xE040); } static struct syscon * rk3399_get_syscon(struct rk_pinctrl_softc *sc, uint32_t bank) { if (bank < 2) return (sc->pmu); return (sc->grf); } struct rk_pinctrl_conf rk3399_conf = { .iomux_conf = rk3399_iomux_bank, .iomux_nbanks = nitems(rk3399_iomux_bank), .pin_fixup = rk3399_pin_fixup, .npin_fixup = nitems(rk3399_pin_fixup), .pin_drive = rk3399_pin_drive, .npin_drive = nitems(rk3399_pin_drive), .gpio_bank = rk3399_gpio_bank, .ngpio_bank = nitems(rk3399_gpio_bank), .get_pd_offset = rk3399_get_pd_offset, .get_syscon = rk3399_get_syscon, }; static struct ofw_compat_data compat_data[] = { {"rockchip,rk3288-pinctrl", (uintptr_t)&rk3288_conf}, {"rockchip,rk3328-pinctrl", (uintptr_t)&rk3328_conf}, {"rockchip,rk3399-pinctrl", (uintptr_t)&rk3399_conf}, {NULL, 0} }; static int rk_pinctrl_parse_bias(phandle_t node) { if (OF_hasprop(node, "bias-disable")) return (0); if (OF_hasprop(node, "bias-pull-up")) return (1); if (OF_hasprop(node, "bias-pull-down")) return (2); return (-1); } static int rk_pinctrl_parse_drive(struct rk_pinctrl_softc *sc, phandle_t node, uint32_t bank, uint32_t subbank, uint32_t *drive, uint32_t *offset) { uint32_t value; int i; if (OF_getencprop(node, "drive-strength", &value, sizeof(value)) != 0) return (-1); /* Map to the correct drive value */ for (i = 0; i < sc->conf->npin_drive; i++) { if (sc->conf->pin_drive[i].bank != bank && sc->conf->pin_drive[i].subbank != subbank) continue; if (sc->conf->pin_drive[i].ma == value) { *drive = sc->conf->pin_drive[i].value; return (0); } } return (-1); } static void rk_pinctrl_get_fixup(struct rk_pinctrl_softc *sc, uint32_t bank, uint32_t pin, uint32_t *reg, uint32_t *mask, uint32_t *bit) { int i; for (i = 0; i < sc->conf->npin_fixup; i++) if (sc->conf->pin_fixup[i].bank == bank && sc->conf->pin_fixup[i].pin == pin) { *reg = sc->conf->pin_fixup[i].reg; *mask = sc->conf->pin_fixup[i].mask; *bit = sc->conf->pin_fixup[i].bit; return; } } static int rk_pinctrl_handle_io(struct rk_pinctrl_softc *sc, phandle_t node, uint32_t bank, uint32_t pin) { bool have_cfg, have_direction, have_value; uint32_t direction_value, pin_value; struct rk_pinctrl_gpio *gpio; int i, rv; have_cfg = false; have_direction = false; have_value = false; /* Get (subset of) GPIO pin properties. */ if (OF_hasprop(node, "output-disable")) { have_cfg = true; have_direction = true; direction_value = GPIO_PIN_INPUT; } if (OF_hasprop(node, "output-enable")) { have_cfg = true; have_direction = true; direction_value = GPIO_PIN_OUTPUT; } if (OF_hasprop(node, "output-low")) { have_cfg = true; have_direction = true; direction_value = GPIO_PIN_OUTPUT; have_value = true; pin_value = 0; } if (OF_hasprop(node, "output-high")) { have_cfg = true; have_direction = true; direction_value = GPIO_PIN_OUTPUT; have_value = true; pin_value = 1; } if (!have_cfg) return (0); /* Find gpio */ gpio = NULL; for(i = 0; i < sc->conf->ngpio_bank; i++) { if (bank == sc->conf->gpio_bank[i].bank) { gpio = sc->conf->gpio_bank + i; break; } } if (gpio == NULL) { device_printf(sc->dev, "Cannot find GPIO bank %d\n", bank); return (ENXIO); } if (gpio->gpio_dev == NULL) { device_printf(sc->dev, "No GPIO subdevice found for bank %d\n", bank); return (ENXIO); } rv = 0; if (have_value) { rv = GPIO_PIN_SET(gpio->gpio_dev, pin, pin_value); if (rv != 0) { device_printf(sc->dev, "Cannot set GPIO value: %d\n", rv); return (rv); } } if (have_direction) { rv = GPIO_PIN_SETFLAGS(gpio->gpio_dev, pin, direction_value); if (rv != 0) { device_printf(sc->dev, "Cannot set GPIO direction: %d\n", rv); return (rv); } } return (0); } static void rk_pinctrl_configure_pin(struct rk_pinctrl_softc *sc, uint32_t *pindata) { phandle_t pin_conf; struct syscon *syscon; uint32_t bank, subbank, pin, function, bias; uint32_t bit, mask, reg, drive; int i, rv; bank = pindata[0]; pin = pindata[1]; function = pindata[2]; pin_conf = OF_node_from_xref(pindata[3]); subbank = pin / 8; for (i = 0; i < sc->conf->iomux_nbanks; i++) if (sc->conf->iomux_conf[i].bank == bank && sc->conf->iomux_conf[i].subbank == subbank) break; if (i == sc->conf->iomux_nbanks) { device_printf(sc->dev, "Unknown pin %d in bank %d\n", pin, bank); return; } /* Find syscon */ syscon = sc->conf->get_syscon(sc, bank); /* Parse pin function */ reg = sc->conf->iomux_conf[i].offset; switch (sc->conf->iomux_conf[i].nbits) { case 4: if ((pin % 8) >= 4) reg += 0x4; bit = (pin % 4) * 4; mask = (0xF << bit); break; case 3: if ((pin % 8) >= 5) reg += 4; bit = (pin % 8 % 5) * 3; mask = (0x7 << bit); break; case 2: bit = (pin % 8) * 2; mask = (0x3 << bit); break; default: device_printf(sc->dev, "Unknown pin stride width %d in bank %d\n", sc->conf->iomux_conf[i].nbits, bank); return; } rk_pinctrl_get_fixup(sc, bank, pin, ®, &mask, &bit); /* * NOTE: not all syscon registers uses hi-word write mask, thus * register modify method should be used. * XXXX We should not pass write mask to syscon register * without hi-word write mask. */ SYSCON_MODIFY_4(syscon, reg, mask, function << bit | (mask << 16)); /* Pull-Up/Down */ bias = rk_pinctrl_parse_bias(pin_conf); if (bias >= 0) { reg = sc->conf->get_pd_offset(sc, bank); reg += bank * 0x10 + ((pin / 8) * 0x4); bit = (pin % 8) * 2; mask = (0x3 << bit) << 16; SYSCON_MODIFY_4(syscon, reg, mask, bias << bit | (mask << 16)); } /* Drive Strength */ rv = rk_pinctrl_parse_drive(sc, pin_conf, bank, subbank, &drive, ®); if (rv == 0) { bit = (pin % 8) * 2; mask = (0x3 << bit) << 16; SYSCON_MODIFY_4(syscon, reg, mask, drive << bit | (mask << 16)); } /* Input/Outpot + default level */ rv = rk_pinctrl_handle_io(sc, pin_conf, bank, pin); } static int rk_pinctrl_configure_pins(device_t dev, phandle_t cfgxref) { struct rk_pinctrl_softc *sc; phandle_t node; uint32_t *pins; int i, npins; sc = device_get_softc(dev); node = OF_node_from_xref(cfgxref); npins = OF_getencprop_alloc_multi(node, "rockchip,pins", sizeof(*pins), (void **)&pins); if (npins <= 0) return (ENOENT); for (i = 0; i != npins; i += 4) rk_pinctrl_configure_pin(sc, pins + i); return (0); } static int rk_pinctrl_register_gpio(struct rk_pinctrl_softc *sc, char *gpio_name, device_t gpio_dev) { int i; for(i = 0; i < sc->conf->ngpio_bank; i++) { if (strcmp(gpio_name, sc->conf->gpio_bank[i].gpio_name) != 0) continue; sc->conf->gpio_bank[i].gpio_dev = gpio_dev; return(0); } return (ENXIO); } static int rk_pinctrl_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "RockChip Pinctrl controller"); return (BUS_PROBE_DEFAULT); } static int rk_pinctrl_attach(device_t dev) { struct rk_pinctrl_softc *sc; phandle_t node; device_t cdev; char *gpio_name, *eptr; int rv; sc = device_get_softc(dev); sc->dev = dev; node = ofw_bus_get_node(dev); if (OF_hasprop(node, "rockchip,grf") && syscon_get_by_ofw_property(dev, node, "rockchip,grf", &sc->grf) != 0) { device_printf(dev, "cannot get grf driver handle\n"); return (ENXIO); } /* RK3399,RK3288 has banks in PMU. RK3328 does not have a PMU. */ if (ofw_bus_node_is_compatible(node, "rockchip,rk3399-pinctrl") || ofw_bus_node_is_compatible(node, "rockchip,rk3288-pinctrl")) { if (OF_hasprop(node, "rockchip,pmu") && syscon_get_by_ofw_property(dev, node, "rockchip,pmu", &sc->pmu) != 0) { device_printf(dev, "cannot get pmu driver handle\n"); return (ENXIO); } } sc->conf = (struct rk_pinctrl_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data; fdt_pinctrl_register(dev, "rockchip,pins"); simplebus_init(dev, node); bus_generic_probe(dev); /* Attach child devices */ for (node = OF_child(node); node > 0; node = OF_peer(node)) { if (!ofw_bus_node_is_compatible(node, "rockchip,gpio-bank")) continue; rv = OF_getprop_alloc(node, "name", (void **)&gpio_name); if (rv <= 0) { device_printf(sc->dev, "Cannot GPIO subdevice name.\n"); continue; } cdev = simplebus_add_device(dev, node, 0, NULL, -1, NULL); if (cdev == NULL) { device_printf(dev, " Cannot add GPIO subdevice: %s\n", gpio_name); OF_prop_free(gpio_name); continue; } rv = device_probe_and_attach(cdev); if (rv != 0) { device_printf(sc->dev, "Cannot attach GPIO subdevice: %s\n", gpio_name); OF_prop_free(gpio_name); continue; } /* Grep device name from name property */ eptr = gpio_name; strsep(&eptr, "@"); if (gpio_name == eptr) { device_printf(sc->dev, "Unrecognized format of GPIO subdevice name: %s\n", gpio_name); OF_prop_free(gpio_name); continue; } rv = rk_pinctrl_register_gpio(sc, gpio_name, cdev); if (rv != 0) { device_printf(sc->dev, "Cannot register GPIO subdevice %s: %d\n", gpio_name, rv); OF_prop_free(gpio_name); continue; } OF_prop_free(gpio_name); } fdt_pinctrl_configure_tree(dev); return (bus_generic_attach(dev)); } static int rk_pinctrl_detach(device_t dev) { return (EBUSY); } static device_method_t rk_pinctrl_methods[] = { /* Device interface */ DEVMETHOD(device_probe, rk_pinctrl_probe), DEVMETHOD(device_attach, rk_pinctrl_attach), DEVMETHOD(device_detach, rk_pinctrl_detach), /* fdt_pinctrl interface */ DEVMETHOD(fdt_pinctrl_configure, rk_pinctrl_configure_pins), DEVMETHOD_END }; static devclass_t rk_pinctrl_devclass; DEFINE_CLASS_1(rk_pinctrl, rk_pinctrl_driver, rk_pinctrl_methods, sizeof(struct rk_pinctrl_softc), simplebus_driver); EARLY_DRIVER_MODULE(rk_pinctrl, simplebus, rk_pinctrl_driver, rk_pinctrl_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); MODULE_VERSION(rk_pinctrl, 1); Index: head/sys/dev/cpufreq/cpufreq_dt.c =================================================================== --- head/sys/dev/cpufreq/cpufreq_dt.c (revision 355356) +++ head/sys/dev/cpufreq/cpufreq_dt.c (revision 355357) @@ -1,546 +1,545 @@ /*- * Copyright (c) 2018 Emmanuel Vadot * Copyright (c) 2016 Jared McNeill - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * Generic DT based cpufreq driver */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cpufreq_if.h" #if 0 #define DEBUG(dev, msg...) device_printf(dev, "cpufreq_dt: " msg); #else #define DEBUG(dev, msg...) #endif enum opp_version { OPP_V1 = 1, OPP_V2, }; struct cpufreq_dt_opp { uint64_t freq; uint32_t uvolt_target; uint32_t uvolt_min; uint32_t uvolt_max; uint32_t uamps; uint32_t clk_latency; bool turbo_mode; bool opp_suspend; }; struct cpufreq_dt_softc { device_t dev; clk_t clk; regulator_t reg; struct cpufreq_dt_opp *opp; ssize_t nopp; cpuset_t cpus; }; static void cpufreq_dt_notify(device_t dev, uint64_t freq) { struct cpufreq_dt_softc *sc; struct pcpu *pc; int cpu; sc = device_get_softc(dev); CPU_FOREACH(cpu) { if (CPU_ISSET(cpu, &sc->cpus)) { pc = pcpu_find(cpu); pc->pc_clock = freq; } } } static const struct cpufreq_dt_opp * cpufreq_dt_find_opp(device_t dev, uint64_t freq) { struct cpufreq_dt_softc *sc; ssize_t n; sc = device_get_softc(dev); DEBUG(dev, "Looking for freq %ju\n", freq); for (n = 0; n < sc->nopp; n++) if (CPUFREQ_CMP(sc->opp[n].freq, freq)) return (&sc->opp[n]); DEBUG(dev, "Couldn't find one\n"); return (NULL); } static void cpufreq_dt_opp_to_setting(device_t dev, const struct cpufreq_dt_opp *opp, struct cf_setting *set) { struct cpufreq_dt_softc *sc; sc = device_get_softc(dev); memset(set, 0, sizeof(*set)); set->freq = opp->freq / 1000000; set->volts = opp->uvolt_target / 1000; set->power = CPUFREQ_VAL_UNKNOWN; set->lat = opp->clk_latency; set->dev = dev; } static int cpufreq_dt_get(device_t dev, struct cf_setting *set) { struct cpufreq_dt_softc *sc; const struct cpufreq_dt_opp *opp; uint64_t freq; sc = device_get_softc(dev); DEBUG(dev, "cpufreq_dt_get\n"); if (clk_get_freq(sc->clk, &freq) != 0) return (ENXIO); opp = cpufreq_dt_find_opp(dev, freq); if (opp == NULL) { device_printf(dev, "Can't find the current freq in opp\n"); return (ENOENT); } cpufreq_dt_opp_to_setting(dev, opp, set); DEBUG(dev, "Current freq %dMhz\n", set->freq); return (0); } static int cpufreq_dt_set(device_t dev, const struct cf_setting *set) { struct cpufreq_dt_softc *sc; const struct cpufreq_dt_opp *opp, *copp; uint64_t freq; int uvolt, error; sc = device_get_softc(dev); if (clk_get_freq(sc->clk, &freq) != 0) { device_printf(dev, "Can't get current clk freq\n"); return (ENXIO); } /* Try to get current valtage by using regulator first. */ error = regulator_get_voltage(sc->reg, &uvolt); if (error != 0) { /* * Try oppoints table as backup way. However, * this is insufficient because the actual processor * frequency may not be in the table. PLL frequency * granularity can be different that granularity of * oppoint table. */ copp = cpufreq_dt_find_opp(sc->dev, freq); if (copp == NULL) { device_printf(dev, "Can't find the current freq in opp\n"); return (ENOENT); } uvolt = copp->uvolt_target; } opp = cpufreq_dt_find_opp(sc->dev, set->freq * 1000000); if (opp == NULL) { device_printf(dev, "Couldn't find an opp for this freq\n"); return (EINVAL); } DEBUG(sc->dev, "Current freq %ju, uvolt: %d\n", freq, uvolt); DEBUG(sc->dev, "Target freq %ju, , uvolt: %d\n", opp->freq, opp->uvolt_target); if (uvolt < opp->uvolt_target) { DEBUG(dev, "Changing regulator from %u to %u\n", uvolt, opp->uvolt_target); error = regulator_set_voltage(sc->reg, opp->uvolt_min, opp->uvolt_max); if (error != 0) { DEBUG(dev, "Failed, backout\n"); return (ENXIO); } } DEBUG(dev, "Setting clk to %ju\n", opp->freq); error = clk_set_freq(sc->clk, opp->freq, CLK_SET_ROUND_DOWN); if (error != 0) { DEBUG(dev, "Failed, backout\n"); /* Restore previous voltage (best effort) */ error = regulator_set_voltage(sc->reg, copp->uvolt_min, copp->uvolt_max); return (ENXIO); } if (uvolt > opp->uvolt_target) { DEBUG(dev, "Changing regulator from %u to %u\n", uvolt, opp->uvolt_target); error = regulator_set_voltage(sc->reg, opp->uvolt_min, opp->uvolt_max); if (error != 0) { DEBUG(dev, "Failed to switch regulator to %d\n", opp->uvolt_target); /* Restore previous CPU frequency (best effort) */ (void)clk_set_freq(sc->clk, copp->freq, 0); return (ENXIO); } } if (clk_get_freq(sc->clk, &freq) == 0) cpufreq_dt_notify(dev, freq); return (0); } static int cpufreq_dt_type(device_t dev, int *type) { if (type == NULL) return (EINVAL); *type = CPUFREQ_TYPE_ABSOLUTE; return (0); } static int cpufreq_dt_settings(device_t dev, struct cf_setting *sets, int *count) { struct cpufreq_dt_softc *sc; ssize_t n; DEBUG(dev, "cpufreq_dt_settings\n"); if (sets == NULL || count == NULL) return (EINVAL); sc = device_get_softc(dev); if (*count < sc->nopp) { *count = (int)sc->nopp; return (E2BIG); } for (n = 0; n < sc->nopp; n++) cpufreq_dt_opp_to_setting(dev, &sc->opp[n], &sets[n]); *count = (int)sc->nopp; return (0); } static void cpufreq_dt_identify(driver_t *driver, device_t parent) { phandle_t node; /* Properties must be listed under node /cpus/cpu@0 */ node = ofw_bus_get_node(parent); /* The cpu@0 node must have the following properties */ if (!OF_hasprop(node, "clocks") || (!OF_hasprop(node, "cpu-supply") && !OF_hasprop(node, "cpu0-supply"))) return; if (!OF_hasprop(node, "operating-points") && !OF_hasprop(node, "operating-points-v2")) return; if (device_find_child(parent, "cpufreq_dt", -1) != NULL) return; if (BUS_ADD_CHILD(parent, 0, "cpufreq_dt", -1) == NULL) device_printf(parent, "add cpufreq_dt child failed\n"); } static int cpufreq_dt_probe(device_t dev) { phandle_t node; node = ofw_bus_get_node(device_get_parent(dev)); if (!OF_hasprop(node, "clocks") || (!OF_hasprop(node, "cpu-supply") && !OF_hasprop(node, "cpu0-supply"))) return (ENXIO); if (!OF_hasprop(node, "operating-points") && !OF_hasprop(node, "operating-points-v2")) return (ENXIO); device_set_desc(dev, "Generic cpufreq driver"); return (BUS_PROBE_GENERIC); } static int cpufreq_dt_oppv1_parse(struct cpufreq_dt_softc *sc, phandle_t node) { uint32_t *opp, lat; ssize_t n; sc->nopp = OF_getencprop_alloc_multi(node, "operating-points", sizeof(uint32_t) * 2, (void **)&opp); if (sc->nopp == -1) return (ENXIO); if (OF_getencprop(node, "clock-latency", &lat, sizeof(lat)) == -1) lat = CPUFREQ_VAL_UNKNOWN; sc->opp = malloc(sizeof(*sc->opp) * sc->nopp, M_DEVBUF, M_WAITOK); for (n = 0; n < sc->nopp; n++) { sc->opp[n].freq = opp[n * 2 + 0] * 1000; sc->opp[n].uvolt_min = opp[n * 2 + 1]; sc->opp[n].uvolt_max = sc->opp[n].uvolt_min; sc->opp[n].uvolt_target = sc->opp[n].uvolt_min; sc->opp[n].clk_latency = lat; if (bootverbose) device_printf(sc->dev, "%ju.%03ju MHz, %u uV\n", sc->opp[n].freq / 1000000, sc->opp[n].freq % 1000000, sc->opp[n].uvolt_target); } free(opp, M_OFWPROP); return (0); } static int cpufreq_dt_oppv2_parse(struct cpufreq_dt_softc *sc, phandle_t node) { phandle_t opp, opp_table, opp_xref; pcell_t cell[2]; uint32_t *volts, lat; int nvolt, i; if (OF_getencprop(node, "operating-points-v2", &opp_xref, sizeof(opp_xref)) == -1) { device_printf(sc->dev, "Cannot get xref to oppv2 table\n"); return (ENXIO); } opp_table = OF_node_from_xref(opp_xref); if (opp_table == opp_xref) return (ENXIO); if (!OF_hasprop(opp_table, "opp-shared")) { device_printf(sc->dev, "Only opp-shared is supported\n"); return (ENXIO); } for (opp = OF_child(opp_table); opp > 0; opp = OF_peer(opp)) sc->nopp += 1; sc->opp = malloc(sizeof(*sc->opp) * sc->nopp, M_DEVBUF, M_WAITOK); for (i = 0, opp_table = OF_child(opp_table); opp_table > 0; opp_table = OF_peer(opp_table), i++) { /* opp-hz is a required property */ if (OF_getencprop(opp_table, "opp-hz", cell, sizeof(cell)) == -1) continue; sc->opp[i].freq = cell[0]; sc->opp[i].freq <<= 32; sc->opp[i].freq |= cell[1]; if (OF_getencprop(opp_table, "clock-latency", &lat, sizeof(lat)) == -1) sc->opp[i].clk_latency = CPUFREQ_VAL_UNKNOWN; else sc->opp[i].clk_latency = (int)lat; if (OF_hasprop(opp_table, "turbo-mode")) sc->opp[i].turbo_mode = true; if (OF_hasprop(opp_table, "opp-suspend")) sc->opp[i].opp_suspend = true; nvolt = OF_getencprop_alloc_multi(opp_table, "opp-microvolt", sizeof(*volts), (void **)&volts); if (nvolt == 1) { sc->opp[i].uvolt_target = volts[0]; sc->opp[i].uvolt_min = volts[0]; sc->opp[i].uvolt_max = volts[0]; } else if (nvolt == 3) { sc->opp[i].uvolt_target = volts[0]; sc->opp[i].uvolt_min = volts[1]; sc->opp[i].uvolt_max = volts[2]; } else { device_printf(sc->dev, "Wrong count of opp-microvolt property\n"); OF_prop_free(volts); free(sc->opp, M_DEVBUF); return (ENXIO); } OF_prop_free(volts); if (bootverbose) device_printf(sc->dev, "%ju.%03ju Mhz (%u uV)\n", sc->opp[i].freq / 1000000, sc->opp[i].freq % 1000000, sc->opp[i].uvolt_target); } return (0); } static int cpufreq_dt_attach(device_t dev) { struct cpufreq_dt_softc *sc; phandle_t node; phandle_t cnode, opp, copp; int cpu; uint64_t freq; int rv = 0; enum opp_version version; sc = device_get_softc(dev); sc->dev = dev; node = ofw_bus_get_node(device_get_parent(dev)); if (regulator_get_by_ofw_property(dev, node, "cpu-supply", &sc->reg) != 0) { if (regulator_get_by_ofw_property(dev, node, "cpu0-supply", &sc->reg) != 0) { device_printf(dev, "no regulator for %s\n", ofw_bus_get_name(device_get_parent(dev))); return (ENXIO); } } if (clk_get_by_ofw_index(dev, node, 0, &sc->clk) != 0) { device_printf(dev, "no clock for %s\n", ofw_bus_get_name(device_get_parent(dev))); regulator_release(sc->reg); return (ENXIO); } if (OF_hasprop(node, "operating-points")) { version = OPP_V1; rv = cpufreq_dt_oppv1_parse(sc, node); if (rv != 0) { device_printf(dev, "Failed to parse opp-v1 table\n"); return (rv); } OF_getencprop(node, "operating-points", &opp, sizeof(opp)); } else { version = OPP_V2; rv = cpufreq_dt_oppv2_parse(sc, node); if (rv != 0) { device_printf(dev, "Failed to parse opp-v2 table\n"); return (rv); } OF_getencprop(node, "operating-points-v2", &opp, sizeof(opp)); } /* * Find all CPUs that share the same opp table */ CPU_ZERO(&sc->cpus); cpu = device_get_unit(device_get_parent(dev)); for (cnode = node; cnode > 0; cnode = OF_peer(cnode), cpu++) { copp = -1; if (version == OPP_V1) OF_getencprop(cnode, "operating-points", &copp, sizeof(copp)); else if (version == OPP_V2) OF_getencprop(cnode, "operating-points-v2", &copp, sizeof(copp)); if (opp == copp) CPU_SET(cpu, &sc->cpus); } if (clk_get_freq(sc->clk, &freq) == 0) cpufreq_dt_notify(dev, freq); cpufreq_register(dev); return (0); } static device_method_t cpufreq_dt_methods[] = { /* Device interface */ DEVMETHOD(device_identify, cpufreq_dt_identify), DEVMETHOD(device_probe, cpufreq_dt_probe), DEVMETHOD(device_attach, cpufreq_dt_attach), /* cpufreq interface */ DEVMETHOD(cpufreq_drv_get, cpufreq_dt_get), DEVMETHOD(cpufreq_drv_set, cpufreq_dt_set), DEVMETHOD(cpufreq_drv_type, cpufreq_dt_type), DEVMETHOD(cpufreq_drv_settings, cpufreq_dt_settings), DEVMETHOD_END }; static driver_t cpufreq_dt_driver = { "cpufreq_dt", cpufreq_dt_methods, sizeof(struct cpufreq_dt_softc), }; static devclass_t cpufreq_dt_devclass; DRIVER_MODULE(cpufreq_dt, cpu, cpufreq_dt_driver, cpufreq_dt_devclass, 0, 0); MODULE_VERSION(cpufreq_dt, 1); Index: head/sys/dev/mmc/host/dwmmc_altera.c =================================================================== --- head/sys/dev/mmc/host/dwmmc_altera.c (revision 355356) +++ head/sys/dev/mmc/host/dwmmc_altera.c (revision 355357) @@ -1,105 +1,104 @@ /* * Copyright 2017 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include "opt_mmccam.h" static struct ofw_compat_data compat_data[] = { {"altr,socfpga-dw-mshc", 1}, {NULL, 0}, }; static int altera_dwmmc_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Synopsys DesignWare Mobile " "Storage Host Controller (Altera)"); return (BUS_PROBE_VENDOR); } static int altera_dwmmc_attach(device_t dev) { struct dwmmc_softc *sc; phandle_t root; sc = device_get_softc(dev); sc->hwtype = HWTYPE_ALTERA; root = OF_finddevice("/"); if (ofw_bus_node_is_compatible(root, "altr,socfpga-stratix10")) { sc->bus_hz = 24000000; sc->use_pio = 1; } return (dwmmc_attach(dev)); } static device_method_t altera_dwmmc_methods[] = { /* bus interface */ DEVMETHOD(device_probe, altera_dwmmc_probe), DEVMETHOD(device_attach, altera_dwmmc_attach), DEVMETHOD_END }; static devclass_t altera_dwmmc_devclass; DEFINE_CLASS_1(altera_dwmmc, altera_dwmmc_driver, altera_dwmmc_methods, sizeof(struct dwmmc_softc), dwmmc_driver); DRIVER_MODULE(altera_dwmmc, simplebus, altera_dwmmc_driver, altera_dwmmc_devclass, 0, 0); DRIVER_MODULE(altera_dwmmc, ofwbus, altera_dwmmc_driver, altera_dwmmc_devclass , NULL, NULL); #ifndef MMCCAM MMC_DECLARE_BRIDGE(altera_dwmmc); #endif Index: head/sys/dev/mmc/host/dwmmc_rockchip.c =================================================================== --- head/sys/dev/mmc/host/dwmmc_rockchip.c (revision 355356) +++ head/sys/dev/mmc/host/dwmmc_rockchip.c (revision 355357) @@ -1,152 +1,151 @@ /* * Copyright 2017 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #ifdef EXT_RESOURCES #include #endif #include #include "opt_mmccam.h" enum RKTYPE { RK2928 = 1, RK3288, }; static struct ofw_compat_data compat_data[] = { {"rockchip,rk2928-dw-mshc", RK2928}, {"rockchip,rk3288-dw-mshc", RK3288}, {NULL, 0}, }; static int dwmmc_rockchip_update_ios(struct dwmmc_softc *sc, struct mmc_ios *ios); static int rockchip_dwmmc_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Synopsys DesignWare Mobile " "Storage Host Controller (RockChip)"); return (BUS_PROBE_VENDOR); } static int rockchip_dwmmc_attach(device_t dev) { struct dwmmc_softc *sc; int type; sc = device_get_softc(dev); sc->hwtype = HWTYPE_ROCKCHIP; type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; switch (type) { case RK2928: sc->use_pio = 1; break; } sc->pwren_inverted = 1; #ifdef EXT_RESOURCES sc->update_ios = &dwmmc_rockchip_update_ios; #endif return (dwmmc_attach(dev)); } #ifdef EXT_RESOURCES static int dwmmc_rockchip_update_ios(struct dwmmc_softc *sc, struct mmc_ios *ios) { unsigned int clock; int error; if (ios->clock && ios->clock != sc->bus_hz) { sc->bus_hz = clock = ios->clock; /* Set the MMC clock. */ if (sc->ciu) { /* * Apparently you need to set the ciu clock to * the double of bus_hz */ error = clk_set_freq(sc->ciu, clock * 2, CLK_SET_ROUND_DOWN); if (error != 0) { device_printf(sc->dev, "failed to set frequency to %u Hz: %d\n", clock, error); return (error); } } } return (0); } #endif static device_method_t rockchip_dwmmc_methods[] = { /* bus interface */ DEVMETHOD(device_probe, rockchip_dwmmc_probe), DEVMETHOD(device_attach, rockchip_dwmmc_attach), DEVMETHOD_END }; static devclass_t rockchip_dwmmc_devclass; DEFINE_CLASS_1(rockchip_dwmmc, rockchip_dwmmc_driver, rockchip_dwmmc_methods, sizeof(struct dwmmc_softc), dwmmc_driver); DRIVER_MODULE(rockchip_dwmmc, simplebus, rockchip_dwmmc_driver, rockchip_dwmmc_devclass, 0, 0); DRIVER_MODULE(rockchip_dwmmc, ofwbus, rockchip_dwmmc_driver, rockchip_dwmmc_devclass, NULL, NULL); #ifndef MMCCAM MMC_DECLARE_BRIDGE(rockchip_dwmmc); #endif Index: head/sys/dev/mmc/host/dwmmc_samsung.c =================================================================== --- head/sys/dev/mmc/host/dwmmc_samsung.c (revision 355356) +++ head/sys/dev/mmc/host/dwmmc_samsung.c (revision 355357) @@ -1,132 +1,131 @@ /* * Copyright 2017 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #define WRITE4(_sc, _reg, _val) \ bus_write_4((_sc)->res[0], _reg, _val) static struct ofw_compat_data compat_data[] = { {"samsung,exynos5420-dw-mshc", 1}, {NULL, 0}, }; static int samsung_dwmmc_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Synopsys DesignWare Mobile " "Storage Host Controller (Samsung)"); return (BUS_PROBE_VENDOR); } static int samsung_dwmmc_attach(device_t dev) { struct dwmmc_softc *sc; pcell_t dts_value[3]; phandle_t node; int len; sc = device_get_softc(dev); sc->hwtype = HWTYPE_EXYNOS; if ((node = ofw_bus_get_node(sc->dev)) == -1) return (ENXIO); if ((len = OF_getproplen(node, "samsung,dw-mshc-ciu-div")) <= 0) return (ENXIO); OF_getencprop(node, "samsung,dw-mshc-ciu-div", dts_value, len); sc->sdr_timing = (dts_value[0] << SDMMC_CLKSEL_DIVIDER_SHIFT); sc->ddr_timing = (dts_value[0] << SDMMC_CLKSEL_DIVIDER_SHIFT); if ((len = OF_getproplen(node, "samsung,dw-mshc-sdr-timing")) <= 0) return (ENXIO); OF_getencprop(node, "samsung,dw-mshc-sdr-timing", dts_value, len); sc->sdr_timing |= ((dts_value[0] << SDMMC_CLKSEL_SAMPLE_SHIFT) | (dts_value[1] << SDMMC_CLKSEL_DRIVE_SHIFT)); if ((len = OF_getproplen(node, "samsung,dw-mshc-ddr-timing")) <= 0) return (ENXIO); OF_getencprop(node, "samsung,dw-mshc-ddr-timing", dts_value, len); sc->ddr_timing |= ((dts_value[0] << SDMMC_CLKSEL_SAMPLE_SHIFT) | (dts_value[1] << SDMMC_CLKSEL_DRIVE_SHIFT)); WRITE4(sc, EMMCP_MPSBEGIN0, 0); WRITE4(sc, EMMCP_SEND0, 0); WRITE4(sc, EMMCP_CTRL0, (MPSCTRL_SECURE_READ_BIT | MPSCTRL_SECURE_WRITE_BIT | MPSCTRL_NON_SECURE_READ_BIT | MPSCTRL_NON_SECURE_WRITE_BIT | MPSCTRL_VALID)); return (dwmmc_attach(dev)); } static device_method_t samsung_dwmmc_methods[] = { /* bus interface */ DEVMETHOD(device_probe, samsung_dwmmc_probe), DEVMETHOD(device_attach, samsung_dwmmc_attach), DEVMETHOD_END }; static devclass_t samsung_dwmmc_devclass; DEFINE_CLASS_1(samsung_dwmmc, samsung_dwmmc_driver, samsung_dwmmc_methods, sizeof(struct dwmmc_softc), dwmmc_driver); DRIVER_MODULE(samsung_dwmmc, simplebus, samsung_dwmmc_driver, samsung_dwmmc_devclass, 0, 0); DRIVER_MODULE(samsung_dwmmc, ofwbus, samsung_dwmmc_driver, samsung_dwmmc_devclass , NULL, NULL); #ifndef MMCCAM MMC_DECLARE_BRIDGE(samsung_dwmmc); #endif Index: head/sys/dev/pwm/ofw_pwm.c =================================================================== --- head/sys/dev/pwm/ofw_pwm.c (revision 355356) +++ head/sys/dev/pwm/ofw_pwm.c (revision 355357) @@ -1,101 +1,100 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include int pwm_get_by_ofw_propidx(device_t consumer, phandle_t node, const char *prop_name, int idx, pwm_channel_t *out_channel) { phandle_t xref; pcell_t *cells; struct pwm_channel channel; int ncells, rv; rv = ofw_bus_parse_xref_list_alloc(node, prop_name, "#pwm-cells", idx, &xref, &ncells, &cells); if (rv != 0) return (rv); channel.dev = OF_device_from_xref(xref); if (channel.dev == NULL) { OF_prop_free(cells); return (ENODEV); } channel.channel = cells[0]; channel.period = cells[1]; if (ncells >= 3) channel.flags = cells[2]; *out_channel = malloc(sizeof(struct pwm_channel), M_DEVBUF, M_WAITOK | M_ZERO); **out_channel = channel; return (0); } int pwm_get_by_ofw_idx(device_t consumer, phandle_t node, int idx, pwm_channel_t *out_channel) { return (pwm_get_by_ofw_propidx(consumer, node, "pwms", idx, out_channel)); } int pwm_get_by_ofw_property(device_t consumer, phandle_t node, const char *prop_name, pwm_channel_t *out_channel) { return (pwm_get_by_ofw_propidx(consumer, node, prop_name, 0, out_channel)); } int pwm_get_by_ofw_name(device_t consumer, phandle_t node, const char *name, pwm_channel_t *out_channel) { int rv, idx; rv = ofw_bus_find_string_index(node, "pwm-names", name, &idx); if (rv != 0) return (rv); return (pwm_get_by_ofw_idx(consumer, node, idx, out_channel)); } Index: head/sys/dev/pwm/ofw_pwm.h =================================================================== --- head/sys/dev/pwm/ofw_pwm.h (revision 355356) +++ head/sys/dev/pwm/ofw_pwm.h (revision 355357) @@ -1,55 +1,54 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _OFW_PWM_H_ #define _OFW_PWM_H_ #include struct pwm_channel { device_t dev; u_int channel; uint64_t period; uint64_t duty; uint32_t flags; bool enabled; }; typedef struct pwm_channel *pwm_channel_t; int pwm_get_by_ofw_propidx(device_t consumer, phandle_t node, const char *prop_name, int idx, pwm_channel_t *channel); int pwm_get_by_ofw_idx(device_t consumer, phandle_t node, int idx, pwm_channel_t *out_channel); int pwm_get_by_ofw_property(device_t consumer, phandle_t node, const char *prop_name, pwm_channel_t *out_channel); int pwm_get_by_ofw_name(device_t consumer, phandle_t node, const char *name, pwm_channel_t *out_channel); #endif /* _OFW_PWM_H_ */ Index: head/sys/dev/pwm/pwmbus.c =================================================================== --- head/sys/dev/pwm/pwmbus.c (revision 355356) +++ head/sys/dev/pwm/pwmbus.c (revision 355357) @@ -1,293 +1,292 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include "pwmbus_if.h" /* * bus_if methods... */ static device_t pwmbus_add_child(device_t dev, u_int order, const char *name, int unit) { device_t child; struct pwmbus_ivars *ivars; child = device_add_child_ordered(dev, order, name, unit); if (child == NULL) return (child); ivars = malloc(sizeof(struct pwmbus_ivars), M_DEVBUF, M_NOWAIT | M_ZERO); if (ivars == NULL) { device_delete_child(dev, child); return (NULL); } device_set_ivars(child, ivars); return (child); } static int pwmbus_child_location_str(device_t dev, device_t child, char *buf, size_t blen) { struct pwmbus_ivars *ivars; ivars = device_get_ivars(child); snprintf(buf, blen, "hwdev=%s channel=%u", device_get_nameunit(device_get_parent(dev)), ivars->pi_channel); return (0); } static int pwmbus_child_pnpinfo_str(device_t dev, device_t child, char *buf, size_t buflen) { *buf = '\0'; return (0); } static void pwmbus_hinted_child(device_t dev, const char *dname, int dunit) { struct pwmbus_ivars *ivars; device_t child; child = pwmbus_add_child(dev, 0, dname, dunit); /* * If there is a channel hint, use it. Otherwise pi_channel was * initialized to zero, so that's the channel we'll use. */ ivars = device_get_ivars(child); resource_int_value(dname, dunit, "channel", &ivars->pi_channel); } static int pwmbus_print_child(device_t dev, device_t child) { struct pwmbus_ivars *ivars; int rv; ivars = device_get_ivars(child); rv = bus_print_child_header(dev, child); rv += printf(" channel %u", ivars->pi_channel); rv += bus_print_child_footer(dev, child); return (rv); } static void pwmbus_probe_nomatch(device_t dev, device_t child) { struct pwmbus_ivars *ivars; ivars = device_get_ivars(child); if (ivars != NULL) device_printf(dev, " on channel %u\n", ivars->pi_channel); return; } static int pwmbus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { struct pwmbus_ivars *ivars; ivars = device_get_ivars(child); switch (which) { case PWMBUS_IVAR_CHANNEL: *(u_int *)result = ivars->pi_channel; break; default: return (EINVAL); } return (0); } /* * device_if methods... */ static int pwmbus_probe(device_t dev) { device_set_desc(dev, "PWM bus"); return (BUS_PROBE_GENERIC); } static int pwmbus_attach(device_t dev) { struct pwmbus_softc *sc; struct pwmbus_ivars *ivars; device_t child, parent; u_int chan; sc = device_get_softc(dev); sc->dev = dev; parent = device_get_parent(dev); if (PWMBUS_CHANNEL_COUNT(parent, &sc->nchannels) != 0 || sc->nchannels == 0) { device_printf(sc->dev, "No channels on parent %s\n", device_get_nameunit(parent)); return (ENXIO); } /* Add a pwmc(4) child for each channel. */ for (chan = 0; chan < sc->nchannels; ++chan) { if ((child = pwmbus_add_child(sc->dev, 0, "pwmc", -1)) == NULL) { device_printf(dev, "failed to add pwmc child device " "for channel %u\n", chan); continue; } ivars = device_get_ivars(child); ivars->pi_channel = chan; } bus_enumerate_hinted_children(dev); bus_generic_probe(dev); return (bus_generic_attach(dev)); } static int pwmbus_detach(device_t dev) { int rv; if ((rv = bus_generic_detach(dev)) == 0) rv = device_delete_children(dev); return (rv); } /* * pwmbus_if methods... */ static int pwmbus_channel_config(device_t dev, u_int chan, u_int period, u_int duty) { return (PWMBUS_CHANNEL_CONFIG(device_get_parent(dev), chan, period, duty)); } static int pwmbus_channel_get_config(device_t dev, u_int chan, u_int *period, u_int *duty) { return (PWMBUS_CHANNEL_GET_CONFIG(device_get_parent(dev), chan, period, duty)); } static int pwmbus_channel_get_flags(device_t dev, u_int chan, uint32_t *flags) { return (PWMBUS_CHANNEL_GET_FLAGS(device_get_parent(dev), chan, flags)); } static int pwmbus_channel_enable(device_t dev, u_int chan, bool enable) { return (PWMBUS_CHANNEL_ENABLE(device_get_parent(dev), chan, enable)); } static int pwmbus_channel_set_flags(device_t dev, u_int chan, uint32_t flags) { return (PWMBUS_CHANNEL_SET_FLAGS(device_get_parent(dev), chan, flags)); } static int pwmbus_channel_is_enabled(device_t dev, u_int chan, bool *enable) { return (PWMBUS_CHANNEL_IS_ENABLED(device_get_parent(dev), chan, enable)); } static int pwmbus_channel_count(device_t dev, u_int *nchannel) { return (PWMBUS_CHANNEL_COUNT(device_get_parent(dev), nchannel)); } static device_method_t pwmbus_methods[] = { /* device_if */ DEVMETHOD(device_probe, pwmbus_probe), DEVMETHOD(device_attach, pwmbus_attach), DEVMETHOD(device_detach, pwmbus_detach), /* bus_if */ DEVMETHOD(bus_add_child, pwmbus_add_child), DEVMETHOD(bus_child_location_str, pwmbus_child_location_str), DEVMETHOD(bus_child_pnpinfo_str, pwmbus_child_pnpinfo_str), DEVMETHOD(bus_hinted_child, pwmbus_hinted_child), DEVMETHOD(bus_print_child, pwmbus_print_child), DEVMETHOD(bus_probe_nomatch, pwmbus_probe_nomatch), DEVMETHOD(bus_read_ivar, pwmbus_read_ivar), /* pwmbus_if */ DEVMETHOD(pwmbus_channel_count, pwmbus_channel_count), DEVMETHOD(pwmbus_channel_config, pwmbus_channel_config), DEVMETHOD(pwmbus_channel_get_config, pwmbus_channel_get_config), DEVMETHOD(pwmbus_channel_set_flags, pwmbus_channel_set_flags), DEVMETHOD(pwmbus_channel_get_flags, pwmbus_channel_get_flags), DEVMETHOD(pwmbus_channel_enable, pwmbus_channel_enable), DEVMETHOD(pwmbus_channel_is_enabled, pwmbus_channel_is_enabled), DEVMETHOD_END }; driver_t pwmbus_driver = { "pwmbus", pwmbus_methods, sizeof(struct pwmbus_softc), }; devclass_t pwmbus_devclass; EARLY_DRIVER_MODULE(pwmbus, pwm, pwmbus_driver, pwmbus_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); MODULE_VERSION(pwmbus, 1); Index: head/sys/dev/pwm/pwmc.c =================================================================== --- head/sys/dev/pwm/pwmc.c (revision 355356) +++ head/sys/dev/pwm/pwmc.c (revision 355357) @@ -1,211 +1,210 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include "pwmbus_if.h" #ifdef FDT #include #include #include static struct ofw_compat_data compat_data[] = { {"freebsd,pwmc", true}, {NULL, false}, }; PWMBUS_FDT_PNP_INFO(compat_data); #endif struct pwmc_softc { device_t dev; struct cdev *cdev; u_int chan; }; static int pwm_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) { struct pwmc_softc *sc; struct pwm_state state; device_t bus; int rv = 0; sc = dev->si_drv1; bus = device_get_parent(sc->dev); switch (cmd) { case PWMSETSTATE: bcopy(data, &state, sizeof(state)); rv = PWMBUS_CHANNEL_CONFIG(bus, sc->chan, state.period, state.duty); if (rv == 0) rv = PWMBUS_CHANNEL_ENABLE(bus, sc->chan, state.enable); break; case PWMGETSTATE: bcopy(data, &state, sizeof(state)); rv = PWMBUS_CHANNEL_GET_CONFIG(bus, sc->chan, &state.period, &state.duty); if (rv != 0) return (rv); rv = PWMBUS_CHANNEL_IS_ENABLED(bus, sc->chan, &state.enable); if (rv != 0) return (rv); bcopy(&state, data, sizeof(state)); break; } return (rv); } static struct cdevsw pwm_cdevsw = { .d_version = D_VERSION, .d_name = "pwmc", .d_ioctl = pwm_ioctl }; static void pwmc_setup_label(struct pwmc_softc *sc) { const char *hintlabel; #ifdef FDT void *label; if (OF_getprop_alloc(ofw_bus_get_node(sc->dev), "label", &label) > 0) { make_dev_alias(sc->cdev, "pwm/%s", (char *)label); OF_prop_free(label); } #endif if (resource_string_value(device_get_name(sc->dev), device_get_unit(sc->dev), "label", &hintlabel) == 0) { make_dev_alias(sc->cdev, "pwm/%s", hintlabel); } } static int pwmc_probe(device_t dev) { int rv; rv = BUS_PROBE_NOWILDCARD; #ifdef FDT if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) { rv = BUS_PROBE_DEFAULT; } #endif device_set_desc(dev, "PWM Control"); return (rv); } static int pwmc_attach(device_t dev) { struct pwmc_softc *sc; struct make_dev_args args; int error; sc = device_get_softc(dev); sc->dev = dev; if ((error = pwmbus_get_channel(dev, &sc->chan)) != 0) return (error); make_dev_args_init(&args); args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK; args.mda_devsw = &pwm_cdevsw; args.mda_uid = UID_ROOT; args.mda_gid = GID_OPERATOR; args.mda_mode = 0660; args.mda_si_drv1 = sc; error = make_dev_s(&args, &sc->cdev, "pwm/pwmc%d.%d", device_get_unit(device_get_parent(dev)), sc->chan); if (error != 0) { device_printf(dev, "Failed to make PWM device\n"); return (error); } pwmc_setup_label(sc); return (0); } static int pwmc_detach(device_t dev) { struct pwmc_softc *sc; sc = device_get_softc(dev); destroy_dev(sc->cdev); return (0); } static device_method_t pwmc_methods[] = { /* device_if */ DEVMETHOD(device_probe, pwmc_probe), DEVMETHOD(device_attach, pwmc_attach), DEVMETHOD(device_detach, pwmc_detach), DEVMETHOD_END }; static driver_t pwmc_driver = { "pwmc", pwmc_methods, sizeof(struct pwmc_softc), }; static devclass_t pwmc_devclass; DRIVER_MODULE(pwmc, pwmbus, pwmc_driver, pwmc_devclass, 0, 0); MODULE_DEPEND(pwmc, pwmbus, 1, 1, 1); MODULE_VERSION(pwmc, 1); Index: head/sys/dev/pwm/pwmc.h =================================================================== --- head/sys/dev/pwm/pwmc.h (revision 355356) +++ head/sys/dev/pwm/pwmc.h (revision 355357) @@ -1,51 +1,50 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _PWM_H_ #define _PWM_H_ #define PWM_POLARITY_INVERTED (1 << 0) struct pwm_state { u_int period; u_int duty; uint32_t flags; bool enable; }; /* * ioctls */ #define PWMGETSTATE _IOWR('G', 0, struct pwm_state) #define PWMSETSTATE _IOWR('G', 1, struct pwm_state) #endif /* _PWM_H_ */ Index: head/sys/dev/usb/controller/generic_usb_if.m =================================================================== --- head/sys/dev/usb/controller/generic_usb_if.m (revision 355356) +++ head/sys/dev/usb/controller/generic_usb_if.m (revision 355357) @@ -1,60 +1,59 @@ #- # Copyright (c) 2016 Emmanuel Vadot -# All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # INTERFACE generic_usb; CODE { static int generic_usb_default_init(device_t dev) { return (0); } static int generic_usb_default_deinit(device_t dev) { return (0); } }; HEADER { }; # # Initialize the SoC bits # METHOD int init { device_t dev; } DEFAULT generic_usb_default_init; # # Deinitialize the SoC bits # METHOD int deinit { device_t dev; } DEFAULT generic_usb_default_deinit; Index: head/usr.sbin/pwm/pwm.c =================================================================== --- head/usr.sbin/pwm/pwm.c (revision 355356) +++ head/usr.sbin/pwm/pwm.c (revision 355357) @@ -1,208 +1,207 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Emmanuel Vadot - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PWM_ENABLE 0x0001 #define PWM_DISABLE 0x0002 #define PWM_SHOW_CONFIG 0x0004 #define PWM_PERIOD 0x0008 #define PWM_DUTY 0x0010 static char device_name[PATH_MAX] = "/dev/pwm/pwmc0.0"; static void set_device_name(const char *name) { if (name[0] == '/') strlcpy(device_name, name, sizeof(device_name)); else snprintf(device_name, sizeof(device_name), "/dev/pwm/%s", name); } static void usage(void) { fprintf(stderr, "Usage:\n"); fprintf(stderr, "\tpwm [-f dev] -C\n"); fprintf(stderr, "\tpwm [-f dev] [-D | -E] [-p period] [-d duty[%%]]\n"); exit(1); } int main(int argc, char *argv[]) { struct pwm_state state; int fd; int period, duty; int action, ch; cap_rights_t right_ioctl; const unsigned long pwm_ioctls[] = {PWMGETSTATE, PWMSETSTATE}; char *percent; bool setname; action = 0; setname = false; fd = -1; period = duty = -1; while ((ch = getopt(argc, argv, "f:EDCp:d:")) != -1) { switch (ch) { case 'E': if (action & (PWM_DISABLE | PWM_SHOW_CONFIG)) usage(); action |= PWM_ENABLE; break; case 'D': if (action & (PWM_ENABLE | PWM_SHOW_CONFIG)) usage(); action |= PWM_DISABLE; break; case 'C': if (action) usage(); action = PWM_SHOW_CONFIG; break; case 'p': if (action & PWM_SHOW_CONFIG) usage(); action |= PWM_PERIOD; period = strtol(optarg, NULL, 10); break; case 'd': if (action & PWM_SHOW_CONFIG) usage(); action |= PWM_DUTY; duty = strtol(optarg, &percent, 10); if (*percent == '%') { if (duty < 0 || duty > 100) { fprintf(stderr, "Invalid duty percentage\n"); usage(); } } else if (*percent != '\0') usage(); break; case 'f': setname = true; set_device_name(optarg); break; case '?': usage(); break; } } if (action == 0) usage(); if ((fd = open(device_name, O_RDWR)) == -1) { fprintf(stderr, "pwm: cannot open %s: %s\n", device_name, strerror(errno)); if (setname) exit(1); else usage(); } if (caph_limit_stdio() < 0) { fprintf(stderr, "can't limit stdio rights"); goto fail; } caph_cache_catpages(); cap_rights_init(&right_ioctl, CAP_IOCTL); if (caph_rights_limit(fd, &right_ioctl) < 0) { fprintf(stderr, "cap_right_limit() failed\n"); goto fail; } if (caph_ioctls_limit(fd, pwm_ioctls, nitems(pwm_ioctls)) < 0) { fprintf(stderr, "caph_ioctls_limit() failed\n"); goto fail; } if (caph_enter() < 0) { fprintf(stderr, "failed to enter capability mode\n"); goto fail; } /* Fill the common args */ if (ioctl(fd, PWMGETSTATE, &state) == -1) { fprintf(stderr, "Cannot get current state of the pwm controller\n"); goto fail; } if (action == PWM_SHOW_CONFIG) { printf("period: %u\nduty: %u\nenabled:%d\n", state.period, state.duty, state.enable); goto fail; } else { if (action & PWM_ENABLE) state.enable = true; if (action & PWM_DISABLE) state.enable = false; if (action & PWM_PERIOD) state.period = period; if (action & PWM_DUTY) { if (*percent != '\0') state.duty = state.period * duty / 100; else state.duty = duty; } if (ioctl(fd, PWMSETSTATE, &state) == -1) { fprintf(stderr, "Cannot configure the pwm controller\n"); goto fail; } } close(fd); return (0); fail: close(fd); return (1); }