diff mbox

[OpenWrt-Devel] lantiq: add support for ARV7506PW11 (Alice/O2 IAD 4421)

Message ID 1463557077-19088-1-git-send-email-oswald.buddenhagen@gmx.de
State Changes Requested
Delegated to: John Crispin
Headers show

Commit Message

Oswald Buddenhagen May 18, 2016, 7:37 a.m. UTC
Ethernet, WiFi, ADSL2+, and LEDS are fully functional.

The RFkill switch doesn't appear to be correctly configured.

Supporting the two TAE ports and SIP gateway was not attempted.

The firmware image needs to be kept below ~3.6MiB due to brnboot's dual
image magic. This is just enough for the above configuration plus
dropbear. Luci and other non-critical packages must be installed into
the jffs2 once the device has booted.

U-boot support was not attempted.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 .../linux/lantiq/base-files/etc/board.d/02_network |   8 +
 .../etc/hotplug.d/firmware/10-rt2x00-eeprom        |   2 +-
 target/linux/lantiq/dts/ARV7506PW11.dts            | 213 +++++++++++++++++++++
 target/linux/lantiq/image/Makefile                 |   2 +
 target/linux/lantiq/xway/profiles/arv.mk           |  12 ++
 5 files changed, 236 insertions(+), 1 deletion(-)
 create mode 100644 target/linux/lantiq/dts/ARV7506PW11.dts

Comments

Mathias Kresin May 18, 2016, 11:19 a.m. UTC | #1
I got the same device last Weekend and planned to add support for this
device during the next days. Glad to see that most of the work is
already done.

Find my remarks in-line.

2016-05-18 9:37 GMT+02:00 Oswald Buddenhagen <oswald.buddenhagen@gmx.de>:
> Ethernet, WiFi, ADSL2+, and LEDS are fully functional.
>
> The RFkill switch doesn't appear to be correctly configured.
>
> Supporting the two TAE ports and SIP gateway was not attempted.
>
> The firmware image needs to be kept below ~3.6MiB due to brnboot's dual
> image magic. This is just enough for the above configuration plus
> dropbear. Luci and other non-critical packages must be installed into
> the jffs2 once the device has booted.
>
> U-boot support was not attempted.

I'll give it a try. Lately, I worked a lot with u-boot, so I'm
confident that it shouldn't be that problem.

But I need to identify the boot_sel pins first. I have looked at it
only briefly and was only able to identify one of the boot_sel pins:
R77. Unfortunately this pin alone doesn't switch the SoC to UART mode.
Did you found already the other pins?

> Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
> ---
>  .../linux/lantiq/base-files/etc/board.d/02_network |   8 +
>  .../etc/hotplug.d/firmware/10-rt2x00-eeprom        |   2 +-
>  target/linux/lantiq/dts/ARV7506PW11.dts            | 213 +++++++++++++++++++++
>  target/linux/lantiq/image/Makefile                 |   2 +
>  target/linux/lantiq/xway/profiles/arv.mk           |  12 ++
>  5 files changed, 236 insertions(+), 1 deletion(-)
>  create mode 100644 target/linux/lantiq/dts/ARV7506PW11.dts
>
> diff --git a/target/linux/lantiq/base-files/etc/board.d/02_network b/target/linux/lantiq/base-files/etc/board.d/02_network
> index b27b802..1f06c26 100755
> --- a/target/linux/lantiq/base-files/etc/board.d/02_network
> +++ b/target/linux/lantiq/base-files/etc/board.d/02_network
> @@ -39,6 +39,14 @@ ACMP252|GIGASX76X)
>                 "4:lan:1" "3:lan:2" "2:lan:3" "1:lan:4" "5t@eth0"
>         ;;
>
> +# rtl8306g
> +ARV7506PW11)
> +       lan_mac=$(mtd_get_mac_binary board_config 22)
> +       wan_mac=$(macaddr_add "$lan_mac" 1)
> +       ucidef_add_switch "switch0" \
> +               "4:lan:1" "3:lan:2" "2:lan:3" "1:lan:4" "5t@eth0"
> +       ;;
> +
>  # ar8316
>  ARV4519PW|ARV7510PW22|ARV7518PW|ARV752DPW22|ARV8539PW22)
>         ucidef_add_switch "switch0" \
> diff --git a/target/linux/lantiq/base-files/etc/hotplug.d/firmware/10-rt2x00-eeprom b/target/linux/lantiq/base-files/etc/hotplug.d/firmware/10-rt2x00-eeprom
> index 5f1cb00..da10797 100644
> --- a/target/linux/lantiq/base-files/etc/hotplug.d/firmware/10-rt2x00-eeprom
> +++ b/target/linux/lantiq/base-files/etc/hotplug.d/firmware/10-rt2x00-eeprom
> @@ -35,7 +35,7 @@ case "$FIRMWARE" in
>  "RT2860.eeprom" )
>         local board=$(lantiq_board_name)
>         case $board in
> -       ARV7510PW22|ARV7519PW|ARV752DPW|ARV752DPW22|VGV7519)
> +       ARV7506PW11|ARV7510PW22|ARV7519PW|ARV752DPW|ARV752DPW22|VGV7519)
>                 rt2x00_eeprom_extract "board_config" 520 256 1
>                 ;;
>         ARV7525PW)
> diff --git a/target/linux/lantiq/dts/ARV7506PW11.dts b/target/linux/lantiq/dts/ARV7506PW11.dts
> new file mode 100644
> index 0000000..bb9ffd4
> --- /dev/null
> +++ b/target/linux/lantiq/dts/ARV7506PW11.dts
> @@ -0,0 +1,213 @@
> +/dts-v1/;
> +
> +/include/ "danube.dtsi"
> +
> +/ {
> +       model = "ARV7506PW11 - Alice/O2 IAD 4421";
> +
> +       chosen {
> +               leds {
> +                       boot = &power;
> +                       failsafe = &power_red;
> +                       running = &power;
> +
> +                       dsl = &dsl;
> +                       internet = &internet;
> +                       wifi = &wlan;
> +               };
> +       };
> +
> +       memory@0 {
> +               reg = <0x0 0x4000000>;
> +       };
> +
> +       sram@1F000000 {
> +               vmmc@107000 {
> +                       status = "okay";
> +                       gpios = <&gpiomm 1 0>;
> +               };
> +       };
> +
> +       fpi@10000000 {
> +               localbus@0 {
> +                       nor-boot@0 {
> +                               compatible = "lantiq,nor";
> +                               bank-width = <2>;
> +                               reg = <0 0x0 0x800000>;
> +
> +                               partitions {
> +                                       compatible = "fixed-partitions";
> +                                       #address-cells = <1>;
> +                                       #size-cells = <1>;
> +
> +                                       partition@0 {
> +                                               label = "brnboot";
> +                                               reg = <0x00000 0x20000>;
> +                                               read-only;
> +                                       };
> +
> +                                       partition@20000 {
> +                                               label = "stuff";
> +                                               reg = <0x20000 0x70000>;
> +                                       };

Please add the real layout here and use proper names for the partitions!

> +
> +                                       partition@90000 {
> +                                               label = "rootfs_data";
> +                                               reg = <0x90000 0x3B0000>;
> +                                       };
> +
> +                                       partition@440000 {
> +                                               label = "firmware";
> +                                               reg = <0x440000 0x3B0000>;
> +                                       };

Assuming you're using the brnboot recovery to flash the firmware, this
wont work. brnboot recovery writes alternating to both partitions and
stores the current active one in the Primary Setting partition
(0x80000). Which could results in a situation that the kernel is
stored (and booted) at 0x90000 but the userland + kmods are loaded
from 0x440000. This could lead to a lot of errors and your additional
flash space for volatile data isn't available as well. My patch to use
the current active partition as firmware partition was merged lately
to OpenWrt. Have a look at the VGV7510KW22BRN.dts for reference.

As you already noticed, OpenWrt isn't really usable on devices with a
firmware partition <= 4MB. I would even say, that such are not longer
supported. But that is something the core devs need to decide.

Anyway, I would suggest to focus on u-boot + a custom partition layout
to have enough space for luci and so on.

Mathias
Oswald Buddenhagen May 18, 2016, 9 p.m. UTC | #2
On Wed, May 18, 2016 at 01:19:59PM +0200, Mathias Kresin wrote:
> But I need to identify the boot_sel pins first. I have looked at it
> only briefly and was only able to identify one of the boot_sel pins:
> R77. Unfortunately this pin alone doesn't switch the SoC to UART mode.
> Did you found already the other pins?
> 
no, i didn't bother with analyzing the hardware beyond soft-probing the
gpios to find some led and button pins. the dts is a copy&paste job from
the wiki (which in turn is "derived" from another dts), with a lot of
studying and trial and error to get the bogus parts out of it, and some
polishing and adjustments to recent changes.

you probably noticed that the bootloader is able to dump the dram
registers, which sounds like a nice perk.

> > +                                       partition@20000 {
> > +                                               label = "stuff";
> > +                                               reg = <0x20000 0x70000>;
> > +                                       };
> 
> Please add the real layout here and use proper names for the partitions!
> 
well, i can do that, but the partitions are entirely meaningless in the
used setup.

> > +
> > +                                       partition@90000 {
> > +                                               label = "rootfs_data";
> > +                                               reg = <0x90000 0x3B0000>;
> > +                                       };
> > +
> > +                                       partition@440000 {
> > +                                               label = "firmware";
> > +                                               reg = <0x440000 0x3B0000>;
> > +                                       };
> 
> Assuming you're using the brnboot recovery to flash the firmware, this
> wont work. brnboot recovery writes alternating to both partitions and
> stores the current active one in the Primary Setting partition
> (0x80000).
>
yes. i always first entered the bootloader console, set the active
partition to 0 (so it would overwrite 1), and only then booted the
recovery firmware.

i also had to disable the partition splitter which would use the few
kilobytes behind the image to create rootfs_data.

not a particularly smart setup in retrospect, but that's what the wiki
page maneuvered me into, and i didn't want to invest yet more time in
figuring out alternatives.

> My patch to use the current active partition as firmware partition
> was merged lately to OpenWrt.
>
i know, that's what i mentioned in the other patch.

> Have a look at the VGV7510KW22BRN.dts for reference.
> 
i'll do that if you don't beat me to it (which you can easily do if you
plan to seriously work on this - beyond email, this is a limited weekend
project for me).

i think i also know why rfkill doesn't work: i forgot to change the
keycode when i decided to switch the key's usage from wps to rfkill.
(facepalm)
Mathias Kresin May 19, 2016, 4:19 p.m. UTC | #3
2016-05-18 23:00 GMT+02:00 Oswald Buddenhagen <oswald.buddenhagen@gmx.de>:
> On Wed, May 18, 2016 at 01:19:59PM +0200, Mathias Kresin wrote:
>> But I need to identify the boot_sel pins first. I have looked at it
>> only briefly and was only able to identify one of the boot_sel pins:
>> R77. Unfortunately this pin alone doesn't switch the SoC to UART mode.
>> Did you found already the other pins?
>>
> no, i didn't bother with analyzing the hardware beyond soft-probing the
> gpios to find some led and button pins. the dts is a copy&paste job from
> the wiki (which in turn is "derived" from another dts), with a lot of
> studying and trial and error to get the bogus parts out of it, and some
> polishing and adjustments to recent changes.

I found the pins to enter UART boot mode. Apply 3,3V to the right side
of R65 and GND to the right side of R80. R80 is partially hidden under
the heatsink of the SoC.

> i'll do that if you don't beat me to it (which you can easily do if you
> plan to seriously work on this - beyond email, this is a limited weekend
> project for me).

From zero to working image in just a weekend. That is indeed amazing.

> i think i also know why rfkill doesn't work: i forgot to change the
> keycode when i decided to switch the key's usage from wps to rfkill.
> (facepalm)

That's something where I've a lack of knowledge. Where does the
keycodes come from?

In the meantime I've added support for this board to u-boot, switched
from brnboot to uImage and to a custom partitions layout with a
firmware partition of 8128 KByte. Means, your image shrinking patches
aren't required any more.

I've pushed all my patches to my github repro:
https://github.com/mkresin/lede. All outlined ways to install u-boot
in https://wiki.openwrt.org/toh/arcadyan/vgv7510kw22#booting_via_uart
should work for this device as well.

Neither the u-boot nor the partition layout should considered as final
versions. I've noticed that danube u-boots are tripple the size as
they were with OpenWrt 12.09. I need to check this first.

I haven't had a closer look to the OpenWrt image, but what I've
noticed so far, is a not lit up WLAN led when the wireless is enabled.
Does it work for you?

Do you plan to work further on this patch or do you consider your
weekend project as finished.

Mathias
Oswald Buddenhagen May 19, 2016, 9:04 p.m. UTC | #4
On Thu, May 19, 2016 at 06:19:35PM +0200, Mathias Kresin wrote:
> I found the pins to enter UART boot mode. Apply 3,3V to the right side
> of R65 and GND to the right side of R80.
>
:)

> R80 is partially hidden under the heatsink of the SoC.
> 
not in my case - clearly, the glueing of the heatsinks isn't exactly
precision work. in fact, only the crystal next to the ram stopped the
sink from sliding off entirely. :D

> 2016-05-18 23:00 GMT+02:00 Oswald Buddenhagen <oswald.buddenhagen@gmx.de>:
> > i'll do that if you don't beat me to it (which you can easily do if you
> > plan to seriously work on this - beyond email, this is a limited weekend
> > project for me).
> 
> From zero to working image in just a weekend. That is indeed amazing.
> 
well, i didn't say *one* weekend. ;)
i spent easily 50 hours on that project, though probably i could have
pulled it off in 5 hours if i had known what i'm doing. now i know more
about wifi drivers, pci busses and devicetrees than i ever wanted or
needed to. :D

but i really didn't start from zero - the dts at
https://wiki.openwrt.org/toh/arcadyan/arv7506 is almost complete, even
if broken in a most sinister way. ^^

> > i think i also know why rfkill doesn't work: i forgot to change the
> > keycode when i decided to switch the key's usage from wps to rfkill.
> > (facepalm)
> 
> That's something where I've a lack of knowledge. Where does the
> keycodes come from?
> 
it's in the devicetree. i sent an updated patch. it's not tested,
though.

> In the meantime I've added support for this board to u-boot, switched
> from brnboot to uImage and to a custom partitions layout with a
> firmware partition of 8128 KByte. Means, your image shrinking patches
> aren't required any more.
> 
cool.

> I haven't had a closer look to the OpenWrt image, but what I've
> noticed so far, is a not lit up WLAN led when the wireless is enabled.
> Does it work for you?
> 
not out of the box, iirc. i configured it to netdev/wlan0/link+tx+rx,
which works fine. this shouldn't be necessary, so a board case should be
probably added to /target/linux/lantiq/base-files/etc/board.d/01_leds.
just amend my patch and add a footer mentioning your co-authorship.

> Do you plan to work further on this patch or do you consider your
> weekend project as finished.
> 
i'll happily hand it off at this point.
diff mbox

Patch

diff --git a/target/linux/lantiq/base-files/etc/board.d/02_network b/target/linux/lantiq/base-files/etc/board.d/02_network
index b27b802..1f06c26 100755
--- a/target/linux/lantiq/base-files/etc/board.d/02_network
+++ b/target/linux/lantiq/base-files/etc/board.d/02_network
@@ -39,6 +39,14 @@  ACMP252|GIGASX76X)
 		"4:lan:1" "3:lan:2" "2:lan:3" "1:lan:4" "5t@eth0"
 	;;
 
+# rtl8306g
+ARV7506PW11)
+	lan_mac=$(mtd_get_mac_binary board_config 22)
+	wan_mac=$(macaddr_add "$lan_mac" 1)
+	ucidef_add_switch "switch0" \
+		"4:lan:1" "3:lan:2" "2:lan:3" "1:lan:4" "5t@eth0"
+	;;
+
 # ar8316
 ARV4519PW|ARV7510PW22|ARV7518PW|ARV752DPW22|ARV8539PW22)
 	ucidef_add_switch "switch0" \
diff --git a/target/linux/lantiq/base-files/etc/hotplug.d/firmware/10-rt2x00-eeprom b/target/linux/lantiq/base-files/etc/hotplug.d/firmware/10-rt2x00-eeprom
index 5f1cb00..da10797 100644
--- a/target/linux/lantiq/base-files/etc/hotplug.d/firmware/10-rt2x00-eeprom
+++ b/target/linux/lantiq/base-files/etc/hotplug.d/firmware/10-rt2x00-eeprom
@@ -35,7 +35,7 @@  case "$FIRMWARE" in
 "RT2860.eeprom" )
 	local board=$(lantiq_board_name)
 	case $board in
-	ARV7510PW22|ARV7519PW|ARV752DPW|ARV752DPW22|VGV7519)
+	ARV7506PW11|ARV7510PW22|ARV7519PW|ARV752DPW|ARV752DPW22|VGV7519)
 		rt2x00_eeprom_extract "board_config" 520 256 1
 		;;
 	ARV7525PW)
diff --git a/target/linux/lantiq/dts/ARV7506PW11.dts b/target/linux/lantiq/dts/ARV7506PW11.dts
new file mode 100644
index 0000000..bb9ffd4
--- /dev/null
+++ b/target/linux/lantiq/dts/ARV7506PW11.dts
@@ -0,0 +1,213 @@ 
+/dts-v1/;
+
+/include/ "danube.dtsi"
+
+/ {
+	model = "ARV7506PW11 - Alice/O2 IAD 4421";
+
+	chosen {
+		leds {
+			boot = &power;
+			failsafe = &power_red;
+			running = &power;
+
+			dsl = &dsl;
+			internet = &internet;
+			wifi = &wlan;
+		};
+	};
+
+	memory@0 {
+		reg = <0x0 0x4000000>;
+	};
+
+	sram@1F000000 {
+		vmmc@107000 {
+			status = "okay";
+			gpios = <&gpiomm 1 0>;
+		};
+	};
+
+	fpi@10000000 {
+		localbus@0 {
+			nor-boot@0 {
+				compatible = "lantiq,nor";
+				bank-width = <2>;
+				reg = <0 0x0 0x800000>;
+
+				partitions {
+					compatible = "fixed-partitions";
+					#address-cells = <1>;
+					#size-cells = <1>;
+
+					partition@0 {
+						label = "brnboot";
+						reg = <0x00000 0x20000>;
+						read-only;
+					};
+
+					partition@20000 {
+						label = "stuff";
+						reg = <0x20000 0x70000>;
+					};
+
+					partition@90000 {
+						label = "rootfs_data";
+						reg = <0x90000 0x3B0000>;
+					};
+
+					partition@440000 {
+						label = "firmware";
+						reg = <0x440000 0x3B0000>;
+					};
+
+					partition@7f0000 {
+						label = "board_config";
+						reg = <0x7f0000 0x10000>;
+						read-only;
+					};
+				};
+			};
+
+			mac_addr {
+				compatible = "lantiq,eth-mac";
+				reg = <0 0x7f0016 0x6>;
+				mac-increment = <2>;
+			};
+
+			gpiomm: gpiomm@4000000 {
+				compatible = "lantiq,gpio-mm";
+				reg = <1 0x0 0x10 >;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				lantiq,shadow = <0x3>;
+			};
+		};
+
+		gpio: pinmux@E100B10 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&state_default>;
+
+			state_default: pinmux {
+				ebu {
+					lantiq,groups = "ebu cs1";
+					lantiq,function = "ebu";
+				};
+				exin {
+					lantiq,groups = "exin1";
+					lantiq,function = "exin";
+				};
+				pci_in {
+					lantiq,groups = "req2", "req1";
+					lantiq,function = "pci";
+					lantiq,pull = <2>;
+					lantiq,output = <0>;
+				};
+				pci_out {
+					lantiq,groups = "gnt1";
+					lantiq,function = "pci";
+					lantiq,output = <1>;
+				};
+				pci_rst {
+					lantiq,pins = "io21";
+					lantiq,pull = <2>;
+					lantiq,output = <1>;
+				};
+				switch_rst {
+					lantiq,pins = "io19";
+				};
+				leds {
+					lantiq,pins = "io2", "io3", "io4", "io5", "io6", "io7", "io8", "io9", "io20";
+					lantiq,output = <1>;
+					lantiq,pull = <0>;
+				};
+				keys {
+					lantiq,pins = "io11", "io30";
+					lantiq,output = <0>;
+					lantiq,pull = <2>;
+				};
+			};
+		};
+
+		ifxhcd@E101000 {
+			status = "okay";
+			gpios = <&gpiomm 0 0>;
+		};
+
+		etop@E180000 {
+			phy-mode = "rmii";
+		};
+
+		pci@E105400 {
+			status = "okay";
+			gpio-reset = <&gpio 21 0>;
+		};
+
+	};
+
+	ralink_eep {
+		compatible = "ralink,eeprom";
+		ralink,eeprom = "RT2860.eeprom";
+	};
+
+	gpio-keys-polled {
+		compatible = "gpio-keys-polled";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		poll-interval = <100>;
+
+		rfkill {
+			/* The button is labeled WLAN/WPS. The former seems more useful. */
+			label = "rfkill";
+			gpios = <&gpio 11 1>;
+			linux,code = <0x211>;
+		};
+		reset {
+			label = "reset";
+			gpios = <&gpio 30 1>;
+			linux,code = <0x198>;
+		};
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+		wlan: wlan {
+			label = "arv7506pw11:green:wlan";
+			gpios = <&gpio 2 1>;
+		};
+		power: power {
+			label = "arv7506pw11:green:power";
+			gpios = <&gpio 3 1>;
+		};
+		dsl: dsl {
+			label = "arv7506pw11:green:dsl";
+			gpios = <&gpio 4 1>;
+		};
+		internet: internet {
+			label = "arv7506pw11:green:internet";
+			gpios = <&gpio 5 1>;
+		};
+		power_red: power_red {
+			label = "arv7506pw11:red:power";
+			gpios = <&gpio 6 1>;
+		};
+		internet_red {
+			label = "arv7506pw11:red:internet";
+			gpios = <&gpio 7 1>;
+		};
+		info {
+			label = "arv7506pw11:green:info";
+			gpios = <&gpio 8 1>;
+		};
+		telefon {
+			label = "arv7506pw11:green:telefon";
+			gpios = <&gpio 9 1>;
+		};
+		info_red {
+			label = "arv7506pw11:red:info";
+			gpios = <&gpio 20 1>;
+		};
+	};
+};
diff --git a/target/linux/lantiq/image/Makefile b/target/linux/lantiq/image/Makefile
index bc74e4f..7a5a564 100644
--- a/target/linux/lantiq/image/Makefile
+++ b/target/linux/lantiq/image/Makefile
@@ -352,6 +352,8 @@  ifeq ($(CONFIG_TARGET_lantiq_xway),y)
 Image/BuildKernel/Profile/BTHOMEHUBV2B=$(call Image/BuildKernel/Template,BTHOMEHUBV2B)
 Image/Build/Profile/BTHOMEHUBV2B=$(call Image/BuildNAND/$(1),$(1),BTHOMEHUBV2B)
 
+$(eval $(call lantiqBrnImage,ARV7506PW11,BRNDA4421,0x7AB7ADAD,0x2083b8ed))
+
 $(eval $(call lantiqImage,EASY50712))
 $(eval $(call lantiqImage,ACMP252))
 $(eval $(call lantiqImage,ARV4510PW))
diff --git a/target/linux/lantiq/xway/profiles/arv.mk b/target/linux/lantiq/xway/profiles/arv.mk
index 976cd19..e20e403 100644
--- a/target/linux/lantiq/xway/profiles/arv.mk
+++ b/target/linux/lantiq/xway/profiles/arv.mk
@@ -78,6 +78,18 @@  endef
 
 $(eval $(call Profile,ARV4519PW))
 
+define Profile/ARV7506PW11
+  NAME:=Alice/O2 IAD 4421 - ARV7506PW11
+  PACKAGES:= \
+	kmod-ltq-adsl-danube-mei kmod-ltq-adsl-danube \
+	kmod-ltq-adsl-danube-fw-b kmod-ltq-atm-danube \
+	ltq-adsl-app ppp-mod-pppoa \
+	kmod-rt2800-pci wpad-mini \
+	swconfig
+endef
+
+$(eval $(call Profile,ARV7506PW11))
+
 define Profile/ARV7510PW22
   NAME:=Astoria - ARV7510PW22
   PACKAGES:=kmod-ltq-hcd-danube kmod-ledtrig-usbdev \