2023-05-30 11:32:59

by Adam Ford

[permalink] [raw]
Subject: [RFC 1/3] clk: renesas: rcar-gen3: Add support for ZG clock

A clock used for the 3D graphics appears to be common
among multiple SoC's, so add a generic gen3 clock
for clocking the graphics.

Signed-off-by: Adam Ford <[email protected]>

diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c
index b3ef62fa612e..7abfbf77a497 100644
--- a/drivers/clk/renesas/rcar-gen3-cpg.c
+++ b/drivers/clk/renesas/rcar-gen3-cpg.c
@@ -301,6 +301,39 @@ static struct clk * __init cpg_z_clk_register(const char *name,
return clk;
}

+static struct clk * __init cpg_zg_clk_register(const char *name,
+ const char *parent_name,
+ void __iomem *reg,
+ unsigned int div,
+ unsigned int offset)
+{
+ struct clk_init_data init;
+ struct cpg_z_clk *zclk;
+ struct clk *clk;
+
+ zclk = kzalloc(sizeof(*zclk), GFP_KERNEL);
+ if (!zclk)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &cpg_z_clk_ops;
+ init.flags = 0;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ zclk->reg = reg + CPG_FRQCRB;
+ zclk->kick_reg = reg + CPG_FRQCRB;
+ zclk->hw.init = &init;
+ zclk->mask = GENMASK(offset + 4, offset);
+ zclk->fixed_div = div; /* PLLVCO x 1/div1 x 3DGE divider x 1/div2 */
+
+ clk = clk_register(NULL, &zclk->hw);
+ if (IS_ERR(clk))
+ kfree(zclk);
+
+ return clk;
+}
+
static const struct clk_div_table cpg_rpcsrc_div_table[] = {
{ 2, 5 }, { 3, 6 }, { 0, 0 },
};
@@ -502,6 +535,9 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
case CLK_TYPE_GEN3_RPCD2:
return cpg_rpcd2_clk_register(core->name, base + CPG_RPCCKCR,
__clk_get_name(parent));
+ case CLK_TYPE_GEN3_ZG:
+ return cpg_zg_clk_register(core->name, __clk_get_name(parent),
+ base, core->div, core->offset);

default:
return ERR_PTR(-EINVAL);
diff --git a/drivers/clk/renesas/rcar-gen3-cpg.h b/drivers/clk/renesas/rcar-gen3-cpg.h
index 9028bf4295ce..bfdc649bdf12 100644
--- a/drivers/clk/renesas/rcar-gen3-cpg.h
+++ b/drivers/clk/renesas/rcar-gen3-cpg.h
@@ -22,6 +22,7 @@ enum rcar_gen3_clk_types {
CLK_TYPE_GEN3_R,
CLK_TYPE_GEN3_MDSEL, /* Select parent/divider using mode pin */
CLK_TYPE_GEN3_Z,
+ CLK_TYPE_GEN3_ZG,
CLK_TYPE_GEN3_OSC, /* OSC EXTAL predivider and fixed divider */
CLK_TYPE_GEN3_RCKSEL, /* Select parent/divider using RCKCR.CKSEL */
CLK_TYPE_GEN3_RPCSRC,
--
2.39.2



2023-05-30 11:40:27

by Adam Ford

[permalink] [raw]
Subject: [RFC 3/3] arm64: dts: renesas: r8a774a1: Add GPU Node

With the 3dge and ZG clocks now available, the generic GPU node can
be added. Until proper firmware is made, it is not usable.

Signed-off-by: Adam Ford <[email protected]>
---
This is based on the assumption that the Rogue 6250 could use
generic driver [1] and firmware [2] being implemebted by the Mesa group
and others. In practice, the firmware isn't really compatible since
the 6250 in the RZ/G2M appears to be a different variant.

[1] - https://gitlab.freedesktop.org/frankbinns/powervr/-/tree/powervr-next
[2] - https://gitlab.freedesktop.org/frankbinns/linux-firmware/-/tree/powervr/powervr

diff --git a/arch/arm64/boot/dts/renesas/r8a774a1.dtsi b/arch/arm64/boot/dts/renesas/r8a774a1.dtsi
index c21b78685123..7e5816113a3c 100644
--- a/arch/arm64/boot/dts/renesas/r8a774a1.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a774a1.dtsi
@@ -226,6 +226,27 @@ extalr_clk: extalr {
clock-frequency = <0>;
};

+ gpu_opp_table: opp-table {
+ compatible = "operating-points-v2";
+
+ opp-200000000 {
+ opp-hz = /bits/ 64 <200000000>;
+ opp-microvolt = <830000>;
+ };
+ opp-300000000 {
+ opp-hz = /bits/ 64 <300000000>;
+ opp-microvolt = <830000>;
+ };
+ opp-400000000 {
+ opp-hz = /bits/ 64 <400000000>;
+ opp-microvolt = <830000>;
+ };
+ opp-600000000 {
+ opp-hz = /bits/ 64 <600000000>;
+ opp-microvolt = <830000>;
+ };
+ };
+
/* External PCIe clock - can be overridden by the board */
pcie_bus_clk: pcie_bus {
compatible = "fixed-clock";
@@ -2347,6 +2368,18 @@ gic: interrupt-controller@f1010000 {
resets = <&cpg 408>;
};

+ gpu@fd000000 {
+ compatible = "img,powervr-series6xt";
+ reg = <0 0xfd000000 0 0x40000>;
+ interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cpg CPG_MOD 112>, <&cpg CPG_MOD 112>,<&cpg CPG_MOD 112>;
+ clock-names = "core", "mem", "sys";
+ interrupt-names = "gpu";
+ operating-points-v2 = <&gpu_opp_table>;
+ power-domains = <&sysc R8A774A1_PD_3DG_B>;
+ resets = <&cpg 112>;
+ };
+
pciec0: pcie@fe000000 {
compatible = "renesas,pcie-r8a774a1",
"renesas,pcie-rcar-gen3";
--
2.39.2


2023-05-30 12:04:32

by Adam Ford

[permalink] [raw]
Subject: [RFC 2/3] clk: renesas: r8a7741a: Add 3dge and ZG support

The 3dge and ZG clocks are necessary to support the 3D graphics.

Signed-off-by: Adam Ford <[email protected]>

diff --git a/drivers/clk/renesas/r8a774a1-cpg-mssr.c b/drivers/clk/renesas/r8a774a1-cpg-mssr.c
index ad03c09ebc1f..7e70c9a9affa 100644
--- a/drivers/clk/renesas/r8a774a1-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a774a1-cpg-mssr.c
@@ -76,6 +76,7 @@ static const struct cpg_core_clk r8a774a1_core_clks[] __initconst = {
/* Core Clock Outputs */
DEF_GEN3_Z("z", R8A774A1_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0, 2, 8),
DEF_GEN3_Z("z2", R8A774A1_CLK_Z2, CLK_TYPE_GEN3_Z, CLK_PLL2, 2, 0),
+ DEF_GEN3_Z("zg", R8A774A1_CLK_ZG, CLK_TYPE_GEN3_ZG, CLK_PLL4, 4, 24),
DEF_FIXED("ztr", R8A774A1_CLK_ZTR, CLK_PLL1_DIV2, 6, 1),
DEF_FIXED("ztrd2", R8A774A1_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1),
DEF_FIXED("zt", R8A774A1_CLK_ZT, CLK_PLL1_DIV2, 4, 1),
@@ -123,6 +124,7 @@ static const struct cpg_core_clk r8a774a1_core_clks[] __initconst = {
};

static const struct mssr_mod_clk r8a774a1_mod_clks[] __initconst = {
+ DEF_MOD("3dge", 112, R8A774A1_CLK_ZG),
DEF_MOD("tmu4", 121, R8A774A1_CLK_S0D6),
DEF_MOD("tmu3", 122, R8A774A1_CLK_S3D2),
DEF_MOD("tmu2", 123, R8A774A1_CLK_S3D2),
--
2.39.2


2023-06-07 13:24:50

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [RFC 1/3] clk: renesas: rcar-gen3: Add support for ZG clock

Hi Adam,

On Tue, May 30, 2023 at 1:21 PM Adam Ford <[email protected]> wrote:
> A clock used for the 3D graphics appears to be common
> among multiple SoC's, so add a generic gen3 clock
> for clocking the graphics.
>
> Signed-off-by: Adam Ford <[email protected]>

Thanks for your patch!

> --- a/drivers/clk/renesas/rcar-gen3-cpg.c
> +++ b/drivers/clk/renesas/rcar-gen3-cpg.c
> @@ -301,6 +301,39 @@ static struct clk * __init cpg_z_clk_register(const char *name,
> return clk;
> }
>
> +static struct clk * __init cpg_zg_clk_register(const char *name,
> + const char *parent_name,
> + void __iomem *reg,
> + unsigned int div,
> + unsigned int offset)
> +{
> + struct clk_init_data init;

"= {};", as you do not initialize all fields below.

> + struct cpg_z_clk *zclk;
> + struct clk *clk;
> +
> + zclk = kzalloc(sizeof(*zclk), GFP_KERNEL);
> + if (!zclk)
> + return ERR_PTR(-ENOMEM);
> +
> + init.name = name;
> + init.ops = &cpg_z_clk_ops;
> + init.flags = 0;
> + init.parent_names = &parent_name;
> + init.num_parents = 1;
> +
> + zclk->reg = reg + CPG_FRQCRB;
> + zclk->kick_reg = reg + CPG_FRQCRB;
> + zclk->hw.init = &init;
> + zclk->mask = GENMASK(offset + 4, offset);
> + zclk->fixed_div = div; /* PLLVCO x 1/div1 x 3DGE divider x 1/div2 */
> +
> + clk = clk_register(NULL, &zclk->hw);
> + if (IS_ERR(clk))
> + kfree(zclk);
> +
> + return clk;
> +}

This new function is very similar to the existing cpg_z_clk_register().
The only differences are:
- init.flags = 0 vs. CLK_SET_RATE_PARENT, which should not matter
much,
- register CPG_FRQCRB vs. CPG_FRQCRC.

So I think it would be good to avoid duplication by adding a register
parameter to cpg_z_clk_register(), to pass the Frequency Control Register
offset to use.


> +
> static const struct clk_div_table cpg_rpcsrc_div_table[] = {
> { 2, 5 }, { 3, 6 }, { 0, 0 },
> };
> @@ -502,6 +535,9 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
> case CLK_TYPE_GEN3_RPCD2:
> return cpg_rpcd2_clk_register(core->name, base + CPG_RPCCKCR,
> __clk_get_name(parent));
> + case CLK_TYPE_GEN3_ZG:
> + return cpg_zg_clk_register(core->name, __clk_get_name(parent),
> + base, core->div, core->offset);

Please insert this right below the CLK_TYPE_GEN3_Z case.

> default:
> return ERR_PTR(-EINVAL);

The rest LGTM.

(Ideally, we wouldn't need a new clock type, and could just use
CLK_TYPE_GEN3_Z. But then we would need to add a new field to struct
cpg_core_clk to store the FRQCR offset, as the .offset field is already
in use, which would increase all clock table sizes a lot. Or we can
encode both register and bit offset in .offset...
All of this needs a big overhaul for switching to of_clk_add_hw_provider()
anyway, so I wouldn't bother for now.)

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

2023-06-07 13:26:22

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [RFC 2/3] clk: renesas: r8a7741a: Add 3dge and ZG support

On Tue, May 30, 2023 at 1:21 PM Adam Ford <[email protected]> wrote:
> The 3dge and ZG clocks are necessary to support the 3D graphics.
>
> Signed-off-by: Adam Ford <[email protected]>

Reviewed-by: Geert Uytterhoeven <[email protected]>

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

2023-06-07 13:43:21

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [RFC 3/3] arm64: dts: renesas: r8a774a1: Add GPU Node

Hi Adam,

On Tue, May 30, 2023 at 1:21 PM Adam Ford <[email protected]> wrote:
> With the 3dge and ZG clocks now available, the generic GPU node can
> be added. Until proper firmware is made, it is not usable.
>
> Signed-off-by: Adam Ford <[email protected]>
> ---
> This is based on the assumption that the Rogue 6250 could use
> generic driver [1] and firmware [2] being implemebted by the Mesa group
> and others. In practice, the firmware isn't really compatible since
> the 6250 in the RZ/G2M appears to be a different variant.
>
> [1] - https://gitlab.freedesktop.org/frankbinns/powervr/-/tree/powervr-next
> [2] - https://gitlab.freedesktop.org/frankbinns/linux-firmware/-/tree/powervr/powervr

Thanks for your patch!

> --- a/arch/arm64/boot/dts/renesas/r8a774a1.dtsi
> +++ b/arch/arm64/boot/dts/renesas/r8a774a1.dtsi
> @@ -226,6 +226,27 @@ extalr_clk: extalr {
> clock-frequency = <0>;
> };
>
> + gpu_opp_table: opp-table {
> + compatible = "operating-points-v2";
> +
> + opp-200000000 {
> + opp-hz = /bits/ 64 <200000000>;
> + opp-microvolt = <830000>;
> + };
> + opp-300000000 {
> + opp-hz = /bits/ 64 <300000000>;
> + opp-microvolt = <830000>;
> + };
> + opp-400000000 {
> + opp-hz = /bits/ 64 <400000000>;
> + opp-microvolt = <830000>;
> + };
> + opp-600000000 {
> + opp-hz = /bits/ 64 <600000000>;
> + opp-microvolt = <830000>;
> + };
> + };
> +
> /* External PCIe clock - can be overridden by the board */
> pcie_bus_clk: pcie_bus {
> compatible = "fixed-clock";
> @@ -2347,6 +2368,18 @@ gic: interrupt-controller@f1010000 {
> resets = <&cpg 408>;
> };
>
> + gpu@fd000000 {
> + compatible = "img,powervr-series6xt";
> + reg = <0 0xfd000000 0 0x40000>;
> + interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
> + clocks = <&cpg CPG_MOD 112>, <&cpg CPG_MOD 112>,<&cpg CPG_MOD 112>;
> + clock-names = "core", "mem", "sys";
> + interrupt-names = "gpu";
> + operating-points-v2 = <&gpu_opp_table>;
> + power-domains = <&sysc R8A774A1_PD_3DG_B>;
> + resets = <&cpg 112>;
> + };
> +
> pciec0: pcie@fe000000 {
> compatible = "renesas,pcie-r8a774a1",
> "renesas,pcie-rcar-gen3";

LGTM. But obviously I cannot take this as-is, as there are no DT bindings
for this device, and it didn't work for you...

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

2023-06-07 13:56:32

by Adam Ford

[permalink] [raw]
Subject: Re: [RFC 3/3] arm64: dts: renesas: r8a774a1: Add GPU Node

On Wed, Jun 7, 2023 at 8:21 AM Geert Uytterhoeven <[email protected]> wrote:
>
> Hi Adam,
>
> On Tue, May 30, 2023 at 1:21 PM Adam Ford <[email protected]> wrote:
> > With the 3dge and ZG clocks now available, the generic GPU node can
> > be added. Until proper firmware is made, it is not usable.
> >
> > Signed-off-by: Adam Ford <[email protected]>
> > ---
> > This is based on the assumption that the Rogue 6250 could use
> > generic driver [1] and firmware [2] being implemebted by the Mesa group
> > and others. In practice, the firmware isn't really compatible since
> > the 6250 in the RZ/G2M appears to be a different variant.
> >
> > [1] - https://gitlab.freedesktop.org/frankbinns/powervr/-/tree/powervr-next
> > [2] - https://gitlab.freedesktop.org/frankbinns/linux-firmware/-/tree/powervr/powervr
>
> Thanks for your patch!
>
> > --- a/arch/arm64/boot/dts/renesas/r8a774a1.dtsi
> > +++ b/arch/arm64/boot/dts/renesas/r8a774a1.dtsi
> > @@ -226,6 +226,27 @@ extalr_clk: extalr {
> > clock-frequency = <0>;
> > };
> >
> > + gpu_opp_table: opp-table {
> > + compatible = "operating-points-v2";
> > +
> > + opp-200000000 {
> > + opp-hz = /bits/ 64 <200000000>;
> > + opp-microvolt = <830000>;
> > + };
> > + opp-300000000 {
> > + opp-hz = /bits/ 64 <300000000>;
> > + opp-microvolt = <830000>;
> > + };
> > + opp-400000000 {
> > + opp-hz = /bits/ 64 <400000000>;
> > + opp-microvolt = <830000>;
> > + };
> > + opp-600000000 {
> > + opp-hz = /bits/ 64 <600000000>;
> > + opp-microvolt = <830000>;
> > + };
> > + };
> > +
> > /* External PCIe clock - can be overridden by the board */
> > pcie_bus_clk: pcie_bus {
> > compatible = "fixed-clock";
> > @@ -2347,6 +2368,18 @@ gic: interrupt-controller@f1010000 {
> > resets = <&cpg 408>;
> > };
> >
> > + gpu@fd000000 {
> > + compatible = "img,powervr-series6xt";
> > + reg = <0 0xfd000000 0 0x40000>;
> > + interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&cpg CPG_MOD 112>, <&cpg CPG_MOD 112>,<&cpg CPG_MOD 112>;
> > + clock-names = "core", "mem", "sys";
> > + interrupt-names = "gpu";
> > + operating-points-v2 = <&gpu_opp_table>;
> > + power-domains = <&sysc R8A774A1_PD_3DG_B>;
> > + resets = <&cpg 112>;
> > + };
> > +
> > pciec0: pcie@fe000000 {
> > compatible = "renesas,pcie-r8a774a1",
> > "renesas,pcie-rcar-gen3";
>
> LGTM. But obviously I cannot take this as-is, as there are no DT bindings
> for this device, and it didn't work for you...

It was mostly to follow up to the previous ones with links for the
mainline Rogue video driver in the hopes that someone from Renesas
might have some input on whether or not Renesas might be able to
support this and have a discussion. I knew when I submitted it that
it wouldn't be accepted which is why I posted it as an RFC.
If I address concerns you have in the previous patches, would you be
OK with me submitting then as a formal patch to at least get the rest
of the system ready in the event the GPU driver/firmware becomes
available? It seems harmless, but I also see the argument that it's
dead code without the GPU node.

If not, I'll shelve this for now, and hope to get some responses from Renesas.

adam
>
> Gr{oetje,eeting}s,
>
> Geert
>
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]
>
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
> -- Linus Torvalds

2023-06-07 14:28:39

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [RFC 3/3] arm64: dts: renesas: r8a774a1: Add GPU Node

Hi Adam,

On Wed, Jun 7, 2023 at 3:31 PM Adam Ford <[email protected]> wrote:
> On Wed, Jun 7, 2023 at 8:21 AM Geert Uytterhoeven <[email protected]> wrote:
> > On Tue, May 30, 2023 at 1:21 PM Adam Ford <[email protected]> wrote:
> > > With the 3dge and ZG clocks now available, the generic GPU node can
> > > be added. Until proper firmware is made, it is not usable.
> > >
> > > Signed-off-by: Adam Ford <[email protected]>
> > > ---
> > > This is based on the assumption that the Rogue 6250 could use
> > > generic driver [1] and firmware [2] being implemebted by the Mesa group
> > > and others. In practice, the firmware isn't really compatible since
> > > the 6250 in the RZ/G2M appears to be a different variant.
> > >
> > > [1] - https://gitlab.freedesktop.org/frankbinns/powervr/-/tree/powervr-next
> > > [2] - https://gitlab.freedesktop.org/frankbinns/linux-firmware/-/tree/powervr/powervr
> >
> > Thanks for your patch!
> >
> > > --- a/arch/arm64/boot/dts/renesas/r8a774a1.dtsi
> > > +++ b/arch/arm64/boot/dts/renesas/r8a774a1.dtsi
> > > @@ -226,6 +226,27 @@ extalr_clk: extalr {
> > > clock-frequency = <0>;
> > > };
> > >
> > > + gpu_opp_table: opp-table {
> > > + compatible = "operating-points-v2";
> > > +
> > > + opp-200000000 {
> > > + opp-hz = /bits/ 64 <200000000>;
> > > + opp-microvolt = <830000>;
> > > + };
> > > + opp-300000000 {
> > > + opp-hz = /bits/ 64 <300000000>;
> > > + opp-microvolt = <830000>;
> > > + };
> > > + opp-400000000 {
> > > + opp-hz = /bits/ 64 <400000000>;
> > > + opp-microvolt = <830000>;
> > > + };
> > > + opp-600000000 {
> > > + opp-hz = /bits/ 64 <600000000>;
> > > + opp-microvolt = <830000>;
> > > + };
> > > + };
> > > +
> > > /* External PCIe clock - can be overridden by the board */
> > > pcie_bus_clk: pcie_bus {
> > > compatible = "fixed-clock";
> > > @@ -2347,6 +2368,18 @@ gic: interrupt-controller@f1010000 {
> > > resets = <&cpg 408>;
> > > };
> > >
> > > + gpu@fd000000 {
> > > + compatible = "img,powervr-series6xt";
> > > + reg = <0 0xfd000000 0 0x40000>;
> > > + interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
> > > + clocks = <&cpg CPG_MOD 112>, <&cpg CPG_MOD 112>,<&cpg CPG_MOD 112>;
> > > + clock-names = "core", "mem", "sys";
> > > + interrupt-names = "gpu";
> > > + operating-points-v2 = <&gpu_opp_table>;
> > > + power-domains = <&sysc R8A774A1_PD_3DG_B>;
> > > + resets = <&cpg 112>;
> > > + };
> > > +
> > > pciec0: pcie@fe000000 {
> > > compatible = "renesas,pcie-r8a774a1",
> > > "renesas,pcie-rcar-gen3";
> >
> > LGTM. But obviously I cannot take this as-is, as there are no DT bindings
> > for this device, and it didn't work for you...
>
> It was mostly to follow up to the previous ones with links for the
> mainline Rogue video driver in the hopes that someone from Renesas
> might have some input on whether or not Renesas might be able to
> support this and have a discussion. I knew when I submitted it that
> it wouldn't be accepted which is why I posted it as an RFC.
> If I address concerns you have in the previous patches, would you be
> OK with me submitting then as a formal patch to at least get the rest
> of the system ready in the event the GPU driver/firmware becomes
> available? It seems harmless, but I also see the argument that it's
> dead code without the GPU node.

The clock patches are almost there, and I'm happy to accept them
when the last rough edges have been removed.

> If not, I'll shelve this for now, and hope to get some responses from Renesas.

Good luck! ;-)

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds