diff --git a/general/package/legacy/ambarella-osdrv-s3l/files/script/load_ambarella b/general/package/legacy/ambarella-osdrv-s3l/files/script/load_ambarella index c51e468b7..11969574e 100755 --- a/general/package/legacy/ambarella-osdrv-s3l/files/script/load_ambarella +++ b/general/package/legacy/ambarella-osdrv-s3l/files/script/load_ambarella @@ -3,6 +3,16 @@ # Ambarella S3L driver bring-up, in the vendor's order: iav and what it needs, # then the sensor, then the DSP microcode. # +# The sensor sits in reset until its driver loads, so a probe to find out which +# driver to load finds nothing. A board profile setting sensor= avoids the +# question and is the path to rely on. Otherwise the pin, which differs by board, +# comes from the device tree and is released here, before iav.ko claims it. +# +# Releasing it is not enough on its own: the sensor also needs a clock to answer +# I2C, and of everything here only its driver starts one. So the probe works only +# if U-Boot left the sensor PLL running, as the Dahua U-Boot on the IP4M-1026E +# does. A board whose U-Boot stops it detects nothing and needs sensor=. +# # iav registers plain character devices and no device class, so mdev never sees # them and the nodes have to be made here. The major comes from /proc/devices; # the minors are fixed. @@ -37,6 +47,49 @@ make_node() { [ -c "/dev/$1" ] || mknod -m 600 "/dev/$1" c "${major}" "$2" } +# The pin in /iav/vinc0/vinrst-gpios, on the SoC's own GPIO. A vendor board may +# put it on an I2C expander, which sysfs numbers differently: leave that alone. +# iav.ko resets with flag bit 0 as the level, so flag 0 is held low. +release_sensor() { + prop=/proc/device-tree/iav/vinc0/vinrst-gpios + soc=/proc/device-tree/apb@e8000000/pinctrl@e8009000/gpio@0 + [ -r "$prop" ] || return 1 + + # shellcheck disable=SC2046 + set -- $(od -An -tu1 -v "$prop") + [ $# -eq 12 ] || return 1 + phandle="$1 $2 $3 $4" + pin=$(($5 << 24 | $6 << 16 | $7 << 8 | $8)) + flags=${12} + + for name in phandle linux,phandle; do + [ -r "$soc/$name" ] || continue + # shellcheck disable=SC2046 + set -- $(od -An -tu1 -v "$soc/$name") + [ "$*" = "$phandle" ] || return 1 + level=high + [ $((flags & 1)) -eq 1 ] && level=low + + echo "$pin" >/sys/class/gpio/export || return 1 + ret=0 + echo "$level" >"/sys/class/gpio/gpio$pin/direction" || ret=1 + # Even after a failed direction: iav.ko can't claim a pin sysfs holds. + echo "$pin" >/sys/class/gpio/unexport || ret=1 + return $ret + done + return 1 +} + +find_sensor() { + sensor=$(fw_printenv -n sensor 2>/dev/null | tr 'A-Z' 'a-z') + # A failed probe may have been stored as "unknown". That must not stop + # this one from trying again. + if [ -z "${sensor}" ] || [ "${sensor}" = unknown ]; then + release_sensor || log_vendor "Sensor reset not released, detection may find nothing" + sensor=$(ipcinfo -s 2>/dev/null | tr 'A-Z' 'a-z') + fi +} + # ipcinfo reports a bare name and cannot tell the interface, so a bare name # means MIPI. imx290 and imx326 also come as LVDS drivers, reached by setting # sensor=imx290_lvds or sensor=imx326_lvds. @@ -62,13 +115,6 @@ sensor_module() { } load_sensor() { - sensor=$(fw_printenv -n sensor 2>/dev/null | tr 'A-Z' 'a-z') - # A failed probe may have been stored as "unknown". That must not stop - # this one from trying again. - if [ -z "${sensor}" ] || [ "${sensor}" = unknown ]; then - sensor=$(ipcinfo -s 2>/dev/null | tr 'A-Z' 'a-z') - fi - if [ -z "${sensor}" ]; then log_vendor "No sensor in the environment and none detected" return 1 @@ -93,6 +139,8 @@ load_microcode() { } insert_ko() { + find_sensor + if ! load iav; then log_vendor "Failed to load iav" return 1