1*949f008fSpatrick /* $OpenBSD: ofw_misc.c,v 1.43 2023/05/17 23:25:45 patrick Exp $ */
286ab2308Skettenis /*
3aa1f5e88Skettenis * Copyright (c) 2017-2021 Mark Kettenis
486ab2308Skettenis *
586ab2308Skettenis * Permission to use, copy, modify, and distribute this software for any
686ab2308Skettenis * purpose with or without fee is hereby granted, provided that the above
786ab2308Skettenis * copyright notice and this permission notice appear in all copies.
886ab2308Skettenis *
986ab2308Skettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1086ab2308Skettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1186ab2308Skettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1286ab2308Skettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1386ab2308Skettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1486ab2308Skettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1586ab2308Skettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1686ab2308Skettenis */
1786ab2308Skettenis
1886ab2308Skettenis #include <sys/types.h>
19e9d39bafSkettenis #include <sys/device.h>
2086ab2308Skettenis #include <sys/malloc.h>
21e9d39bafSkettenis #include <sys/systm.h>
22e9d39bafSkettenis
23e9d39bafSkettenis #include <net/if.h>
24e9d39bafSkettenis #include <net/if_media.h>
2586ab2308Skettenis
2686ab2308Skettenis #include <machine/bus.h>
2786ab2308Skettenis
28e9d39bafSkettenis #include <dev/mii/mii.h>
29e9d39bafSkettenis #include <dev/mii/miivar.h>
3086ab2308Skettenis #include <dev/ofw/openfirm.h>
314c45b354Skettenis #include <dev/ofw/ofw_gpio.h>
32c12728f2Skettenis #include <dev/ofw/ofw_misc.h>
334c45b354Skettenis #include <dev/ofw/ofw_regulator.h>
3486ab2308Skettenis
351c2f50caSkettenis /*
361c2f50caSkettenis * Register maps.
371c2f50caSkettenis */
381c2f50caSkettenis
3986ab2308Skettenis struct regmap {
40b8cbdd99Skettenis int rm_node;
4186ab2308Skettenis uint32_t rm_phandle;
4286ab2308Skettenis bus_space_tag_t rm_tag;
4386ab2308Skettenis bus_space_handle_t rm_handle;
4486ab2308Skettenis bus_size_t rm_size;
4586ab2308Skettenis
4686ab2308Skettenis LIST_ENTRY(regmap) rm_list;
4786ab2308Skettenis };
4886ab2308Skettenis
4986ab2308Skettenis LIST_HEAD(, regmap) regmaps = LIST_HEAD_INITIALIZER(regmap);
5086ab2308Skettenis
5186ab2308Skettenis void
regmap_register(int node,bus_space_tag_t tag,bus_space_handle_t handle,bus_size_t size)5286ab2308Skettenis regmap_register(int node, bus_space_tag_t tag, bus_space_handle_t handle,
5386ab2308Skettenis bus_size_t size)
5486ab2308Skettenis {
5586ab2308Skettenis struct regmap *rm;
5686ab2308Skettenis
5786ab2308Skettenis rm = malloc(sizeof(struct regmap), M_DEVBUF, M_WAITOK);
58b8cbdd99Skettenis rm->rm_node = node;
5917b07209Skettenis rm->rm_phandle = OF_getpropint(node, "phandle", 0);
6086ab2308Skettenis rm->rm_tag = tag;
6186ab2308Skettenis rm->rm_handle = handle;
6286ab2308Skettenis rm->rm_size = size;
6386ab2308Skettenis LIST_INSERT_HEAD(®maps, rm, rm_list);
6486ab2308Skettenis }
6586ab2308Skettenis
6686ab2308Skettenis struct regmap *
regmap_bycompatible(char * compatible)67a31afb08Spatrick regmap_bycompatible(char *compatible)
68a31afb08Spatrick {
69a31afb08Spatrick struct regmap *rm;
70a31afb08Spatrick
71a31afb08Spatrick LIST_FOREACH(rm, ®maps, rm_list) {
72a31afb08Spatrick if (OF_is_compatible(rm->rm_node, compatible))
73a31afb08Spatrick return rm;
74a31afb08Spatrick }
75a31afb08Spatrick
76a31afb08Spatrick return NULL;
77a31afb08Spatrick }
78a31afb08Spatrick
79a31afb08Spatrick struct regmap *
regmap_bynode(int node)80b8cbdd99Skettenis regmap_bynode(int node)
81b8cbdd99Skettenis {
82b8cbdd99Skettenis struct regmap *rm;
83b8cbdd99Skettenis
84b8cbdd99Skettenis LIST_FOREACH(rm, ®maps, rm_list) {
85b8cbdd99Skettenis if (rm->rm_node == node)
86b8cbdd99Skettenis return rm;
87b8cbdd99Skettenis }
88b8cbdd99Skettenis
89b8cbdd99Skettenis return NULL;
90b8cbdd99Skettenis }
91b8cbdd99Skettenis
92b8cbdd99Skettenis struct regmap *
regmap_byphandle(uint32_t phandle)9386ab2308Skettenis regmap_byphandle(uint32_t phandle)
9486ab2308Skettenis {
9586ab2308Skettenis struct regmap *rm;
9686ab2308Skettenis
97a7702439Spatrick if (phandle == 0)
98a7702439Spatrick return NULL;
99a7702439Spatrick
10086ab2308Skettenis LIST_FOREACH(rm, ®maps, rm_list) {
10186ab2308Skettenis if (rm->rm_phandle == phandle)
10286ab2308Skettenis return rm;
10386ab2308Skettenis }
10486ab2308Skettenis
10586ab2308Skettenis return NULL;
10686ab2308Skettenis }
10786ab2308Skettenis
10886ab2308Skettenis void
regmap_write_4(struct regmap * rm,bus_size_t offset,uint32_t value)10986ab2308Skettenis regmap_write_4(struct regmap *rm, bus_size_t offset, uint32_t value)
11086ab2308Skettenis {
11186ab2308Skettenis KASSERT(offset <= rm->rm_size - sizeof(uint32_t));
11286ab2308Skettenis bus_space_write_4(rm->rm_tag, rm->rm_handle, offset, value);
11386ab2308Skettenis }
11486ab2308Skettenis
11586ab2308Skettenis uint32_t
regmap_read_4(struct regmap * rm,bus_size_t offset)11686ab2308Skettenis regmap_read_4(struct regmap *rm, bus_size_t offset)
11786ab2308Skettenis {
11886ab2308Skettenis KASSERT(offset <= rm->rm_size - sizeof(uint32_t));
11986ab2308Skettenis return bus_space_read_4(rm->rm_tag, rm->rm_handle, offset);
12086ab2308Skettenis }
1212ec99202Skettenis
1228f2101caSdlg /*
1238f2101caSdlg * Network interface support.
1248f2101caSdlg */
1258f2101caSdlg
1268f2101caSdlg LIST_HEAD(, if_device) if_devices =
1278f2101caSdlg LIST_HEAD_INITIALIZER(if_devices);
1288f2101caSdlg
1298f2101caSdlg void
if_register(struct if_device * ifd)1308f2101caSdlg if_register(struct if_device *ifd)
1318f2101caSdlg {
1328f2101caSdlg ifd->if_phandle = OF_getpropint(ifd->if_node, "phandle", 0);
1338f2101caSdlg
1348f2101caSdlg LIST_INSERT_HEAD(&if_devices, ifd, if_list);
1358f2101caSdlg }
1368f2101caSdlg
1378f2101caSdlg struct ifnet *
if_bynode(int node)1388f2101caSdlg if_bynode(int node)
1398f2101caSdlg {
1408f2101caSdlg struct if_device *ifd;
1418f2101caSdlg
1428f2101caSdlg LIST_FOREACH(ifd, &if_devices, if_list) {
1438f2101caSdlg if (ifd->if_node == node)
1448f2101caSdlg return (ifd->if_ifp);
1458f2101caSdlg }
1468f2101caSdlg
1478f2101caSdlg return (NULL);
1488f2101caSdlg }
1498f2101caSdlg
1508f2101caSdlg struct ifnet *
if_byphandle(uint32_t phandle)1518f2101caSdlg if_byphandle(uint32_t phandle)
1528f2101caSdlg {
1538f2101caSdlg struct if_device *ifd;
1548f2101caSdlg
155f56e72c6Sdlg if (phandle == 0)
156f56e72c6Sdlg return (NULL);
157f56e72c6Sdlg
1588f2101caSdlg LIST_FOREACH(ifd, &if_devices, if_list) {
1598f2101caSdlg if (ifd->if_phandle == phandle)
1608f2101caSdlg return (ifd->if_ifp);
1618f2101caSdlg }
1628f2101caSdlg
1638f2101caSdlg return (NULL);
1648f2101caSdlg }
1652ec99202Skettenis
1662ec99202Skettenis /*
1672ec99202Skettenis * PHY support.
1682ec99202Skettenis */
1692ec99202Skettenis
1702ec99202Skettenis LIST_HEAD(, phy_device) phy_devices =
1712ec99202Skettenis LIST_HEAD_INITIALIZER(phy_devices);
1722ec99202Skettenis
1732ec99202Skettenis void
phy_register(struct phy_device * pd)1742ec99202Skettenis phy_register(struct phy_device *pd)
1752ec99202Skettenis {
1762ec99202Skettenis pd->pd_cells = OF_getpropint(pd->pd_node, "#phy-cells", 0);
1772ec99202Skettenis pd->pd_phandle = OF_getpropint(pd->pd_node, "phandle", 0);
1782ec99202Skettenis if (pd->pd_phandle == 0)
1792ec99202Skettenis return;
1802ec99202Skettenis
1812ec99202Skettenis LIST_INSERT_HEAD(&phy_devices, pd, pd_list);
1822ec99202Skettenis }
1832ec99202Skettenis
1842ec99202Skettenis int
phy_usb_nop_enable(int node)1854c45b354Skettenis phy_usb_nop_enable(int node)
1864c45b354Skettenis {
1874c45b354Skettenis uint32_t vcc_supply;
1884c45b354Skettenis uint32_t *gpio;
1894c45b354Skettenis int len;
1904c45b354Skettenis
1914c45b354Skettenis vcc_supply = OF_getpropint(node, "vcc-supply", 0);
1924c45b354Skettenis if (vcc_supply)
1934c45b354Skettenis regulator_enable(vcc_supply);
1944c45b354Skettenis
1954c45b354Skettenis len = OF_getproplen(node, "reset-gpios");
1964c45b354Skettenis if (len <= 0)
1974c45b354Skettenis return 0;
1984c45b354Skettenis
1994c45b354Skettenis /* There should only be a single GPIO pin. */
2004c45b354Skettenis gpio = malloc(len, M_TEMP, M_WAITOK);
2014c45b354Skettenis OF_getpropintarray(node, "reset-gpios", gpio, len);
2024c45b354Skettenis
2034c45b354Skettenis gpio_controller_config_pin(gpio, GPIO_CONFIG_OUTPUT);
2044c45b354Skettenis gpio_controller_set_pin(gpio, 1);
2054c45b354Skettenis delay(10000);
2064c45b354Skettenis gpio_controller_set_pin(gpio, 0);
2074c45b354Skettenis
2084c45b354Skettenis free(gpio, M_TEMP, len);
2094c45b354Skettenis
2104c45b354Skettenis return 0;
2114c45b354Skettenis }
2124c45b354Skettenis
2134c45b354Skettenis int
phy_enable_cells(uint32_t * cells)2142ec99202Skettenis phy_enable_cells(uint32_t *cells)
2152ec99202Skettenis {
2162ec99202Skettenis struct phy_device *pd;
2172ec99202Skettenis uint32_t phandle = cells[0];
2184c45b354Skettenis int node;
2192ec99202Skettenis
2202ec99202Skettenis LIST_FOREACH(pd, &phy_devices, pd_list) {
2212ec99202Skettenis if (pd->pd_phandle == phandle)
2222ec99202Skettenis break;
2232ec99202Skettenis }
2242ec99202Skettenis
2252ec99202Skettenis if (pd && pd->pd_enable)
2262ec99202Skettenis return pd->pd_enable(pd->pd_cookie, &cells[1]);
2272ec99202Skettenis
2284c45b354Skettenis node = OF_getnodebyphandle(phandle);
2294c45b354Skettenis if (node == 0)
2304c45b354Skettenis return ENXIO;
2314c45b354Skettenis
2324c45b354Skettenis if (OF_is_compatible(node, "usb-nop-xceiv"))
2334c45b354Skettenis return phy_usb_nop_enable(node);
2344c45b354Skettenis
2354c45b354Skettenis return ENXIO;
2362ec99202Skettenis }
2372ec99202Skettenis
2382ec99202Skettenis uint32_t *
phy_next_phy(uint32_t * cells)2392ec99202Skettenis phy_next_phy(uint32_t *cells)
2402ec99202Skettenis {
2412ec99202Skettenis uint32_t phandle = cells[0];
2422ec99202Skettenis int node, ncells;
2432ec99202Skettenis
2442ec99202Skettenis node = OF_getnodebyphandle(phandle);
2452ec99202Skettenis if (node == 0)
2462ec99202Skettenis return NULL;
2472ec99202Skettenis
2482ec99202Skettenis ncells = OF_getpropint(node, "#phy-cells", 0);
2492ec99202Skettenis return cells + ncells + 1;
2502ec99202Skettenis }
2512ec99202Skettenis
2522ec99202Skettenis int
phy_enable_prop_idx(int node,char * prop,int idx)2533ce5e03eSdlg phy_enable_prop_idx(int node, char *prop, int idx)
2542ec99202Skettenis {
2552ec99202Skettenis uint32_t *phys;
2562ec99202Skettenis uint32_t *phy;
2572ec99202Skettenis int rv = -1;
2582ec99202Skettenis int len;
2592ec99202Skettenis
260074353b3Spatrick len = OF_getproplen(node, prop);
2612ec99202Skettenis if (len <= 0)
2622ec99202Skettenis return -1;
2632ec99202Skettenis
2642ec99202Skettenis phys = malloc(len, M_TEMP, M_WAITOK);
2653ce5e03eSdlg OF_getpropintarray(node, prop, phys, len);
2662ec99202Skettenis
2672ec99202Skettenis phy = phys;
2682ec99202Skettenis while (phy && phy < phys + (len / sizeof(uint32_t))) {
2692ec99202Skettenis if (idx <= 0)
2702ec99202Skettenis rv = phy_enable_cells(phy);
2712ec99202Skettenis if (idx == 0)
2722ec99202Skettenis break;
2732ec99202Skettenis phy = phy_next_phy(phy);
2742ec99202Skettenis idx--;
2752ec99202Skettenis }
2762ec99202Skettenis
2772ec99202Skettenis free(phys, M_TEMP, len);
2782ec99202Skettenis return rv;
2792ec99202Skettenis }
2802ec99202Skettenis
2812ec99202Skettenis int
phy_enable_idx(int node,int idx)2823ce5e03eSdlg phy_enable_idx(int node, int idx)
2833ce5e03eSdlg {
2843ce5e03eSdlg return (phy_enable_prop_idx(node, "phys", idx));
2853ce5e03eSdlg }
2863ce5e03eSdlg
2873ce5e03eSdlg int
phy_enable(int node,const char * name)2882ec99202Skettenis phy_enable(int node, const char *name)
2892ec99202Skettenis {
2902ec99202Skettenis int idx;
2912ec99202Skettenis
2922ec99202Skettenis idx = OF_getindex(node, name, "phy-names");
2932ec99202Skettenis if (idx == -1)
2942ec99202Skettenis return -1;
2952ec99202Skettenis
2962ec99202Skettenis return phy_enable_idx(node, idx);
2972ec99202Skettenis }
2984216024aSpatrick
2994216024aSpatrick /*
3004216024aSpatrick * I2C support.
3014216024aSpatrick */
3024216024aSpatrick
3034216024aSpatrick LIST_HEAD(, i2c_bus) i2c_busses =
3044216024aSpatrick LIST_HEAD_INITIALIZER(i2c_bus);
3054216024aSpatrick
3064216024aSpatrick void
i2c_register(struct i2c_bus * ib)3074216024aSpatrick i2c_register(struct i2c_bus *ib)
3084216024aSpatrick {
3094216024aSpatrick ib->ib_phandle = OF_getpropint(ib->ib_node, "phandle", 0);
3104216024aSpatrick if (ib->ib_phandle == 0)
3114216024aSpatrick return;
3124216024aSpatrick
3134216024aSpatrick LIST_INSERT_HEAD(&i2c_busses, ib, ib_list);
3144216024aSpatrick }
3154216024aSpatrick
3164216024aSpatrick struct i2c_controller *
i2c_bynode(int node)3174216024aSpatrick i2c_bynode(int node)
3184216024aSpatrick {
3194216024aSpatrick struct i2c_bus *ib;
3204216024aSpatrick
3214216024aSpatrick LIST_FOREACH(ib, &i2c_busses, ib_list) {
3224216024aSpatrick if (ib->ib_node == node)
3234216024aSpatrick return ib->ib_ic;
3244216024aSpatrick }
3254216024aSpatrick
3264216024aSpatrick return NULL;
3274216024aSpatrick }
3284216024aSpatrick
3294216024aSpatrick struct i2c_controller *
i2c_byphandle(uint32_t phandle)3304216024aSpatrick i2c_byphandle(uint32_t phandle)
3314216024aSpatrick {
3324216024aSpatrick struct i2c_bus *ib;
3334216024aSpatrick
334a7702439Spatrick if (phandle == 0)
335a7702439Spatrick return NULL;
336a7702439Spatrick
3374216024aSpatrick LIST_FOREACH(ib, &i2c_busses, ib_list) {
3384216024aSpatrick if (ib->ib_phandle == phandle)
3394216024aSpatrick return ib->ib_ic;
3404216024aSpatrick }
3414216024aSpatrick
3424216024aSpatrick return NULL;
3434216024aSpatrick }
3445296b96aSpatrick
3455296b96aSpatrick /*
3465296b96aSpatrick * SFP support.
3475296b96aSpatrick */
3485296b96aSpatrick
3495296b96aSpatrick LIST_HEAD(, sfp_device) sfp_devices =
3505296b96aSpatrick LIST_HEAD_INITIALIZER(sfp_devices);
3515296b96aSpatrick
3525296b96aSpatrick void
sfp_register(struct sfp_device * sd)3535296b96aSpatrick sfp_register(struct sfp_device *sd)
3545296b96aSpatrick {
3555296b96aSpatrick sd->sd_phandle = OF_getpropint(sd->sd_node, "phandle", 0);
3565296b96aSpatrick if (sd->sd_phandle == 0)
3575296b96aSpatrick return;
3585296b96aSpatrick
3595296b96aSpatrick LIST_INSERT_HEAD(&sfp_devices, sd, sd_list);
3605296b96aSpatrick }
3615296b96aSpatrick
3625296b96aSpatrick int
sfp_do_enable(uint32_t phandle,int enable)3639e963265Skettenis sfp_do_enable(uint32_t phandle, int enable)
3649e963265Skettenis {
3659e963265Skettenis struct sfp_device *sd;
3669e963265Skettenis
3679e963265Skettenis if (phandle == 0)
3689e963265Skettenis return ENXIO;
3699e963265Skettenis
3709e963265Skettenis LIST_FOREACH(sd, &sfp_devices, sd_list) {
3719e963265Skettenis if (sd->sd_phandle == phandle)
3729e963265Skettenis return sd->sd_enable(sd->sd_cookie, enable);
3739e963265Skettenis }
3749e963265Skettenis
3759e963265Skettenis return ENXIO;
3769e963265Skettenis }
3779e963265Skettenis
3789e963265Skettenis int
sfp_enable(uint32_t phandle)3799e963265Skettenis sfp_enable(uint32_t phandle)
3809e963265Skettenis {
3819e963265Skettenis return sfp_do_enable(phandle, 1);
3829e963265Skettenis }
3839e963265Skettenis
3849e963265Skettenis int
sfp_disable(uint32_t phandle)3859e963265Skettenis sfp_disable(uint32_t phandle)
3869e963265Skettenis {
3879e963265Skettenis return sfp_do_enable(phandle, 0);
3889e963265Skettenis }
3899e963265Skettenis
3909e963265Skettenis int
sfp_get_sffpage(uint32_t phandle,struct if_sffpage * sff)3915296b96aSpatrick sfp_get_sffpage(uint32_t phandle, struct if_sffpage *sff)
3925296b96aSpatrick {
3935296b96aSpatrick struct sfp_device *sd;
3945296b96aSpatrick
395a7702439Spatrick if (phandle == 0)
396a7702439Spatrick return ENXIO;
397a7702439Spatrick
3985296b96aSpatrick LIST_FOREACH(sd, &sfp_devices, sd_list) {
3995296b96aSpatrick if (sd->sd_phandle == phandle)
4005296b96aSpatrick return sd->sd_get_sffpage(sd->sd_cookie, sff);
4015296b96aSpatrick }
4025296b96aSpatrick
4035296b96aSpatrick return ENXIO;
4045296b96aSpatrick }
4051eb4c955Skettenis
406fff4b955Skettenis #define SFF8472_TCC_XCC 3 /* 10G Ethernet Compliance Codes */
407fff4b955Skettenis #define SFF8472_TCC_XCC_10G_SR (1 << 4)
408fff4b955Skettenis #define SFF8472_TCC_XCC_10G_LR (1 << 5)
409fff4b955Skettenis #define SFF8472_TCC_XCC_10G_LRM (1 << 6)
410fff4b955Skettenis #define SFF8472_TCC_XCC_10G_ER (1 << 7)
411e9d39bafSkettenis #define SFF8472_TCC_ECC 6 /* Ethernet Compliance Codes */
412e9d39bafSkettenis #define SFF8472_TCC_ECC_1000_SX (1 << 0)
413e9d39bafSkettenis #define SFF8472_TCC_ECC_1000_LX (1 << 1)
414e9d39bafSkettenis #define SFF8472_TCC_ECC_1000_CX (1 << 2)
41523de15b6Skettenis #define SFF8472_TCC_ECC_1000_T (1 << 3)
416fff4b955Skettenis #define SFF8472_TCC_SCT 8 /* SFP+ Cable Technology */
417fff4b955Skettenis #define SFF8472_TCC_SCT_PASSIVE (1 << 2)
418fff4b955Skettenis #define SFF8472_TCC_SCT_ACTIVE (1 << 3)
419e9d39bafSkettenis
420e9d39bafSkettenis int
sfp_add_media(uint32_t phandle,struct mii_data * mii)421e9d39bafSkettenis sfp_add_media(uint32_t phandle, struct mii_data *mii)
422e9d39bafSkettenis {
423e9d39bafSkettenis struct if_sffpage sff;
424e9d39bafSkettenis int error;
425e9d39bafSkettenis
426e9d39bafSkettenis memset(&sff, 0, sizeof(sff));
427e9d39bafSkettenis sff.sff_addr = IFSFF_ADDR_EEPROM;
428e9d39bafSkettenis sff.sff_page = 0;
429e9d39bafSkettenis
430e9d39bafSkettenis error = sfp_get_sffpage(phandle, &sff);
431e9d39bafSkettenis if (error)
432e9d39bafSkettenis return error;
433e9d39bafSkettenis
434fff4b955Skettenis /* SFP */
43523de15b6Skettenis if (sff.sff_data[SFF8472_TCC_ECC] & SFF8472_TCC_ECC_1000_SX) {
436e9d39bafSkettenis ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_1000_SX, 0, NULL);
43723de15b6Skettenis mii->mii_media_active = IFM_ETHER | IFM_1000_SX | IFM_FDX;
43823de15b6Skettenis }
43923de15b6Skettenis if (sff.sff_data[SFF8472_TCC_ECC] & SFF8472_TCC_ECC_1000_LX) {
440e9d39bafSkettenis ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_1000_LX, 0, NULL);
44123de15b6Skettenis mii->mii_media_active = IFM_ETHER | IFM_1000_LX | IFM_FDX;
44223de15b6Skettenis }
44323de15b6Skettenis if (sff.sff_data[SFF8472_TCC_ECC] & SFF8472_TCC_ECC_1000_CX) {
444e9d39bafSkettenis ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_1000_CX, 0, NULL);
44523de15b6Skettenis mii->mii_media_active = IFM_ETHER | IFM_1000_CX | IFM_FDX;
44623de15b6Skettenis }
44723de15b6Skettenis if (sff.sff_data[SFF8472_TCC_ECC] & SFF8472_TCC_ECC_1000_T) {
44823de15b6Skettenis ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_1000_T, 0, NULL);
44923de15b6Skettenis mii->mii_media_active = IFM_ETHER | IFM_1000_T | IFM_FDX;
45023de15b6Skettenis }
451e9d39bafSkettenis
452fff4b955Skettenis /* SFP+ */
453fff4b955Skettenis if (sff.sff_data[SFF8472_TCC_XCC] & SFF8472_TCC_XCC_10G_SR) {
454fff4b955Skettenis ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_10G_SR, 0, NULL);
455fff4b955Skettenis mii->mii_media_active = IFM_ETHER | IFM_10G_SR | IFM_FDX;
456fff4b955Skettenis }
457fff4b955Skettenis if (sff.sff_data[SFF8472_TCC_XCC] & SFF8472_TCC_XCC_10G_LR) {
458fff4b955Skettenis ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_10G_LR, 0, NULL);
459fff4b955Skettenis mii->mii_media_active = IFM_ETHER | IFM_10G_LR | IFM_FDX;
460fff4b955Skettenis }
461fff4b955Skettenis if (sff.sff_data[SFF8472_TCC_XCC] & SFF8472_TCC_XCC_10G_LRM) {
462fff4b955Skettenis ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_10G_LRM, 0, NULL);
463fff4b955Skettenis mii->mii_media_active = IFM_ETHER | IFM_10G_LRM | IFM_FDX;
464fff4b955Skettenis }
465fff4b955Skettenis if (sff.sff_data[SFF8472_TCC_XCC] & SFF8472_TCC_XCC_10G_ER) {
466fff4b955Skettenis ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_10G_ER, 0, NULL);
467fff4b955Skettenis mii->mii_media_active = IFM_ETHER | IFM_10G_ER | IFM_FDX;
468fff4b955Skettenis }
469fff4b955Skettenis
470fff4b955Skettenis /* SFP+ DAC */
471fff4b955Skettenis if (sff.sff_data[SFF8472_TCC_SCT] & SFF8472_TCC_SCT_PASSIVE ||
472fff4b955Skettenis sff.sff_data[SFF8472_TCC_SCT] & SFF8472_TCC_SCT_ACTIVE) {
473fff4b955Skettenis ifmedia_add(&mii->mii_media,
474fff4b955Skettenis IFM_ETHER | IFM_10G_SFP_CU, 0, NULL);
475fff4b955Skettenis mii->mii_media_active = IFM_ETHER | IFM_10G_SFP_CU | IFM_FDX;
476fff4b955Skettenis }
477fff4b955Skettenis
478e9d39bafSkettenis return 0;
479e9d39bafSkettenis }
480e9d39bafSkettenis
4811eb4c955Skettenis /*
4821eb4c955Skettenis * PWM support.
4831eb4c955Skettenis */
4841eb4c955Skettenis
4851eb4c955Skettenis LIST_HEAD(, pwm_device) pwm_devices =
4861eb4c955Skettenis LIST_HEAD_INITIALIZER(pwm_devices);
4871eb4c955Skettenis
4881eb4c955Skettenis void
pwm_register(struct pwm_device * pd)4891eb4c955Skettenis pwm_register(struct pwm_device *pd)
4901eb4c955Skettenis {
4911eb4c955Skettenis pd->pd_cells = OF_getpropint(pd->pd_node, "#pwm-cells", 0);
4921eb4c955Skettenis pd->pd_phandle = OF_getpropint(pd->pd_node, "phandle", 0);
4931eb4c955Skettenis if (pd->pd_phandle == 0)
4941eb4c955Skettenis return;
4951eb4c955Skettenis
4961eb4c955Skettenis LIST_INSERT_HEAD(&pwm_devices, pd, pd_list);
4971eb4c955Skettenis
4981eb4c955Skettenis }
4991eb4c955Skettenis
5001eb4c955Skettenis int
pwm_init_state(uint32_t * cells,struct pwm_state * ps)5011eb4c955Skettenis pwm_init_state(uint32_t *cells, struct pwm_state *ps)
5021eb4c955Skettenis {
5031eb4c955Skettenis struct pwm_device *pd;
5041eb4c955Skettenis
5051eb4c955Skettenis LIST_FOREACH(pd, &pwm_devices, pd_list) {
5061eb4c955Skettenis if (pd->pd_phandle == cells[0]) {
5071eb4c955Skettenis memset(ps, 0, sizeof(struct pwm_state));
5081eb4c955Skettenis pd->pd_get_state(pd->pd_cookie, &cells[1], ps);
5091eb4c955Skettenis ps->ps_pulse_width = 0;
5109800a309Spatrick if (pd->pd_cells >= 2)
5111eb4c955Skettenis ps->ps_period = cells[2];
5129800a309Spatrick if (pd->pd_cells >= 3)
5131eb4c955Skettenis ps->ps_flags = cells[3];
5141eb4c955Skettenis return 0;
5151eb4c955Skettenis }
5161eb4c955Skettenis }
5171eb4c955Skettenis
5181eb4c955Skettenis return ENXIO;
5191eb4c955Skettenis }
5201eb4c955Skettenis
5211eb4c955Skettenis int
pwm_get_state(uint32_t * cells,struct pwm_state * ps)5221eb4c955Skettenis pwm_get_state(uint32_t *cells, struct pwm_state *ps)
5231eb4c955Skettenis {
5241eb4c955Skettenis struct pwm_device *pd;
5251eb4c955Skettenis
5261eb4c955Skettenis LIST_FOREACH(pd, &pwm_devices, pd_list) {
5271eb4c955Skettenis if (pd->pd_phandle == cells[0])
5281eb4c955Skettenis return pd->pd_get_state(pd->pd_cookie, &cells[1], ps);
5291eb4c955Skettenis }
5301eb4c955Skettenis
5311eb4c955Skettenis return ENXIO;
5321eb4c955Skettenis }
5331eb4c955Skettenis
5341eb4c955Skettenis int
pwm_set_state(uint32_t * cells,struct pwm_state * ps)5351eb4c955Skettenis pwm_set_state(uint32_t *cells, struct pwm_state *ps)
5361eb4c955Skettenis {
5371eb4c955Skettenis struct pwm_device *pd;
5381eb4c955Skettenis
5391eb4c955Skettenis LIST_FOREACH(pd, &pwm_devices, pd_list) {
5401eb4c955Skettenis if (pd->pd_phandle == cells[0])
5411eb4c955Skettenis return pd->pd_set_state(pd->pd_cookie, &cells[1], ps);
5421eb4c955Skettenis }
5431eb4c955Skettenis
5441eb4c955Skettenis return ENXIO;
5451eb4c955Skettenis }
546047fbc8bSkettenis
547047fbc8bSkettenis /*
548047fbc8bSkettenis * Non-volatile memory support.
549047fbc8bSkettenis */
550047fbc8bSkettenis
551047fbc8bSkettenis LIST_HEAD(, nvmem_device) nvmem_devices =
552047fbc8bSkettenis LIST_HEAD_INITIALIZER(nvmem_devices);
553047fbc8bSkettenis
5541bd1536fSkettenis struct nvmem_cell {
5551bd1536fSkettenis uint32_t nc_phandle;
5561bd1536fSkettenis struct nvmem_device *nc_nd;
5571bd1536fSkettenis bus_addr_t nc_addr;
5581bd1536fSkettenis bus_size_t nc_size;
559eb0ca4d1Skettenis uint32_t nc_offset;
560eb0ca4d1Skettenis uint32_t nc_bitlen;
5611bd1536fSkettenis
5621bd1536fSkettenis LIST_ENTRY(nvmem_cell) nc_list;
5631bd1536fSkettenis };
5641bd1536fSkettenis
5651bd1536fSkettenis LIST_HEAD(, nvmem_cell) nvmem_cells =
5661bd1536fSkettenis LIST_HEAD_INITIALIZER(nvmem_cells);
5671bd1536fSkettenis
5681bd1536fSkettenis void
nvmem_register_child(int node,struct nvmem_device * nd)5691bd1536fSkettenis nvmem_register_child(int node, struct nvmem_device *nd)
5701bd1536fSkettenis {
5711bd1536fSkettenis struct nvmem_cell *nc;
5721bd1536fSkettenis uint32_t phandle;
573eb0ca4d1Skettenis uint32_t reg[2], bits[2] = {};
5741bd1536fSkettenis
5751bd1536fSkettenis phandle = OF_getpropint(node, "phandle", 0);
5761bd1536fSkettenis if (phandle == 0)
5771bd1536fSkettenis return;
5781bd1536fSkettenis
5791bd1536fSkettenis if (OF_getpropintarray(node, "reg", reg, sizeof(reg)) != sizeof(reg))
5801bd1536fSkettenis return;
5811bd1536fSkettenis
582eb0ca4d1Skettenis OF_getpropintarray(node, "bits", bits, sizeof(bits));
583eb0ca4d1Skettenis
5841bd1536fSkettenis nc = malloc(sizeof(struct nvmem_cell), M_DEVBUF, M_WAITOK);
5851bd1536fSkettenis nc->nc_phandle = phandle;
5861bd1536fSkettenis nc->nc_nd = nd;
5871bd1536fSkettenis nc->nc_addr = reg[0];
5881bd1536fSkettenis nc->nc_size = reg[1];
589eb0ca4d1Skettenis nc->nc_offset = bits[0];
590eb0ca4d1Skettenis nc->nc_bitlen = bits[1];
5911bd1536fSkettenis LIST_INSERT_HEAD(&nvmem_cells, nc, nc_list);
5921bd1536fSkettenis }
5931bd1536fSkettenis
594047fbc8bSkettenis void
nvmem_register(struct nvmem_device * nd)595047fbc8bSkettenis nvmem_register(struct nvmem_device *nd)
596047fbc8bSkettenis {
5971bd1536fSkettenis int node;
598047fbc8bSkettenis
5991bd1536fSkettenis nd->nd_phandle = OF_getpropint(nd->nd_node, "phandle", 0);
6001bd1536fSkettenis if (nd->nd_phandle)
601047fbc8bSkettenis LIST_INSERT_HEAD(&nvmem_devices, nd, nd_list);
6021bd1536fSkettenis
6031bd1536fSkettenis for (node = OF_child(nd->nd_node); node; node = OF_peer(node))
6041bd1536fSkettenis nvmem_register_child(node, nd);
605047fbc8bSkettenis }
606047fbc8bSkettenis
607047fbc8bSkettenis int
nvmem_read(uint32_t phandle,bus_addr_t addr,void * data,bus_size_t size)608047fbc8bSkettenis nvmem_read(uint32_t phandle, bus_addr_t addr, void *data, bus_size_t size)
609047fbc8bSkettenis {
610047fbc8bSkettenis struct nvmem_device *nd;
611047fbc8bSkettenis
612a7702439Spatrick if (phandle == 0)
613a7702439Spatrick return ENXIO;
614a7702439Spatrick
615047fbc8bSkettenis LIST_FOREACH(nd, &nvmem_devices, nd_list) {
616047fbc8bSkettenis if (nd->nd_phandle == phandle)
617047fbc8bSkettenis return nd->nd_read(nd->nd_cookie, addr, data, size);
618047fbc8bSkettenis }
619047fbc8bSkettenis
620047fbc8bSkettenis return ENXIO;
621047fbc8bSkettenis }
6221bd1536fSkettenis
6231bd1536fSkettenis int
nvmem_read_cell(int node,const char * name,void * data,bus_size_t size)6241bd1536fSkettenis nvmem_read_cell(int node, const char *name, void *data, bus_size_t size)
6251bd1536fSkettenis {
6261bd1536fSkettenis struct nvmem_device *nd;
6271bd1536fSkettenis struct nvmem_cell *nc;
62898df0a09Skettenis uint8_t *p = data;
62998df0a09Skettenis bus_addr_t addr;
6301bd1536fSkettenis uint32_t phandle, *phandles;
631eb0ca4d1Skettenis uint32_t offset, bitlen;
632eb0ca4d1Skettenis int id, len, first;
6331bd1536fSkettenis
6341bd1536fSkettenis id = OF_getindex(node, name, "nvmem-cell-names");
6351bd1536fSkettenis if (id < 0)
6361bd1536fSkettenis return ENXIO;
6371bd1536fSkettenis
6381bd1536fSkettenis len = OF_getproplen(node, "nvmem-cells");
6391bd1536fSkettenis if (len <= 0)
6401bd1536fSkettenis return ENXIO;
6411bd1536fSkettenis
6421bd1536fSkettenis phandles = malloc(len, M_TEMP, M_WAITOK);
6431bd1536fSkettenis OF_getpropintarray(node, "nvmem-cells", phandles, len);
6441bd1536fSkettenis phandle = phandles[id];
6451bd1536fSkettenis free(phandles, M_TEMP, len);
6461bd1536fSkettenis
6471bd1536fSkettenis LIST_FOREACH(nc, &nvmem_cells, nc_list) {
6481bd1536fSkettenis if (nc->nc_phandle == phandle)
6491bd1536fSkettenis break;
6501bd1536fSkettenis }
6511bd1536fSkettenis if (nc == NULL)
6521bd1536fSkettenis return ENXIO;
6531bd1536fSkettenis
6541bd1536fSkettenis nd = nc->nc_nd;
6552b93968fSkettenis if (nd->nd_read == NULL)
6562b93968fSkettenis return EACCES;
657eb0ca4d1Skettenis
658eb0ca4d1Skettenis first = 1;
65998df0a09Skettenis addr = nc->nc_addr + (nc->nc_offset / 8);
66098df0a09Skettenis offset = nc->nc_offset % 8;
661eb0ca4d1Skettenis bitlen = nc->nc_bitlen;
662eb0ca4d1Skettenis while (bitlen > 0 && size > 0) {
663eb0ca4d1Skettenis uint8_t mask, tmp;
664eb0ca4d1Skettenis int error;
665eb0ca4d1Skettenis
66698df0a09Skettenis error = nd->nd_read(nd->nd_cookie, addr++, &tmp, 1);
667eb0ca4d1Skettenis if (error)
668eb0ca4d1Skettenis return error;
669eb0ca4d1Skettenis
670eb0ca4d1Skettenis if (bitlen >= 8)
671eb0ca4d1Skettenis mask = 0xff;
672eb0ca4d1Skettenis else
673eb0ca4d1Skettenis mask = (1 << bitlen) - 1;
674eb0ca4d1Skettenis
675eb0ca4d1Skettenis if (!first) {
676eb0ca4d1Skettenis *p++ |= (tmp << (8 - offset)) & (mask << (8 - offset));
677eb0ca4d1Skettenis bitlen -= MIN(offset, bitlen);
67898df0a09Skettenis mask >>= offset;
679eb0ca4d1Skettenis size--;
680eb0ca4d1Skettenis }
681eb0ca4d1Skettenis
682eb0ca4d1Skettenis if (bitlen > 0 && size > 0) {
68398df0a09Skettenis *p = (tmp >> offset) & mask;
684eb0ca4d1Skettenis bitlen -= MIN(8 - offset, bitlen);
685eb0ca4d1Skettenis }
686eb0ca4d1Skettenis
687eb0ca4d1Skettenis first = 0;
688eb0ca4d1Skettenis }
689eb0ca4d1Skettenis if (nc->nc_bitlen > 0)
690eb0ca4d1Skettenis return 0;
691eb0ca4d1Skettenis
692eb0ca4d1Skettenis if (size > nc->nc_size)
693eb0ca4d1Skettenis return EINVAL;
694eb0ca4d1Skettenis
6951bd1536fSkettenis return nd->nd_read(nd->nd_cookie, nc->nc_addr, data, size);
6961bd1536fSkettenis }
697f11bbe72Spatrick
6982b93968fSkettenis int
nvmem_write_cell(int node,const char * name,const void * data,bus_size_t size)6992b93968fSkettenis nvmem_write_cell(int node, const char *name, const void *data, bus_size_t size)
7002b93968fSkettenis {
7012b93968fSkettenis struct nvmem_device *nd;
7022b93968fSkettenis struct nvmem_cell *nc;
70398df0a09Skettenis const uint8_t *p = data;
70498df0a09Skettenis bus_addr_t addr;
7052b93968fSkettenis uint32_t phandle, *phandles;
706eb0ca4d1Skettenis uint32_t offset, bitlen;
707eb0ca4d1Skettenis int id, len, first;
7082b93968fSkettenis
7092b93968fSkettenis id = OF_getindex(node, name, "nvmem-cell-names");
7102b93968fSkettenis if (id < 0)
7112b93968fSkettenis return ENXIO;
7122b93968fSkettenis
7132b93968fSkettenis len = OF_getproplen(node, "nvmem-cells");
7142b93968fSkettenis if (len <= 0)
7152b93968fSkettenis return ENXIO;
7162b93968fSkettenis
7172b93968fSkettenis phandles = malloc(len, M_TEMP, M_WAITOK);
7182b93968fSkettenis OF_getpropintarray(node, "nvmem-cells", phandles, len);
7192b93968fSkettenis phandle = phandles[id];
7202b93968fSkettenis free(phandles, M_TEMP, len);
7212b93968fSkettenis
7222b93968fSkettenis LIST_FOREACH(nc, &nvmem_cells, nc_list) {
7232b93968fSkettenis if (nc->nc_phandle == phandle)
7242b93968fSkettenis break;
7252b93968fSkettenis }
7262b93968fSkettenis if (nc == NULL)
7272b93968fSkettenis return ENXIO;
7282b93968fSkettenis
7292b93968fSkettenis nd = nc->nc_nd;
7302b93968fSkettenis if (nd->nd_write == NULL)
7312b93968fSkettenis return EACCES;
732eb0ca4d1Skettenis
733eb0ca4d1Skettenis first = 1;
73498df0a09Skettenis addr = nc->nc_addr + (nc->nc_offset / 8);
73598df0a09Skettenis offset = nc->nc_offset % 8;
736eb0ca4d1Skettenis bitlen = nc->nc_bitlen;
737eb0ca4d1Skettenis while (bitlen > 0 && size > 0) {
738eb0ca4d1Skettenis uint8_t mask, tmp;
739eb0ca4d1Skettenis int error;
740eb0ca4d1Skettenis
74198df0a09Skettenis error = nd->nd_read(nd->nd_cookie, addr, &tmp, 1);
742eb0ca4d1Skettenis if (error)
743eb0ca4d1Skettenis return error;
744eb0ca4d1Skettenis
745eb0ca4d1Skettenis if (bitlen >= 8)
746eb0ca4d1Skettenis mask = 0xff;
747eb0ca4d1Skettenis else
748eb0ca4d1Skettenis mask = (1 << bitlen) - 1;
749eb0ca4d1Skettenis
750eb0ca4d1Skettenis tmp &= ~(mask << offset);
751eb0ca4d1Skettenis tmp |= (*p++ << offset) & (mask << offset);
752eb0ca4d1Skettenis bitlen -= MIN(8 - offset, bitlen);
753eb0ca4d1Skettenis size--;
754eb0ca4d1Skettenis
755eb0ca4d1Skettenis if (!first && bitlen > 0 && size > 0) {
756eb0ca4d1Skettenis tmp &= ~(mask >> (8 - offset));
757eb0ca4d1Skettenis tmp |= (*p >> (8 - offset)) & (mask >> (8 - offset));
758eb0ca4d1Skettenis bitlen -= MIN(offset, bitlen);
759eb0ca4d1Skettenis }
760eb0ca4d1Skettenis
76198df0a09Skettenis error = nd->nd_write(nd->nd_cookie, addr++, &tmp, 1);
762eb0ca4d1Skettenis if (error)
763eb0ca4d1Skettenis return error;
764eb0ca4d1Skettenis
765eb0ca4d1Skettenis first = 0;
766eb0ca4d1Skettenis }
767eb0ca4d1Skettenis if (nc->nc_bitlen > 0)
768eb0ca4d1Skettenis return 0;
769eb0ca4d1Skettenis
770eb0ca4d1Skettenis if (size > nc->nc_size)
771eb0ca4d1Skettenis return EINVAL;
772eb0ca4d1Skettenis
7732b93968fSkettenis return nd->nd_write(nd->nd_cookie, nc->nc_addr, data, size);
7742b93968fSkettenis }
7752b93968fSkettenis
776c2490375Skettenis /* Port/endpoint interface support */
777f11bbe72Spatrick
778c2490375Skettenis LIST_HEAD(, endpoint) endpoints =
779c2490375Skettenis LIST_HEAD_INITIALIZER(endpoints);
780f11bbe72Spatrick
781f11bbe72Spatrick void
endpoint_register(int node,struct device_port * dp,enum endpoint_type type)782c2490375Skettenis endpoint_register(int node, struct device_port *dp, enum endpoint_type type)
783f11bbe72Spatrick {
784c2490375Skettenis struct endpoint *ep;
785c2490375Skettenis
786c2490375Skettenis ep = malloc(sizeof(*ep), M_DEVBUF, M_WAITOK);
787c2490375Skettenis ep->ep_node = node;
788c2490375Skettenis ep->ep_phandle = OF_getpropint(node, "phandle", 0);
789c2490375Skettenis ep->ep_reg = OF_getpropint(node, "reg", -1);
790c2490375Skettenis ep->ep_port = dp;
791c2490375Skettenis ep->ep_type = type;
792c2490375Skettenis
793c2490375Skettenis LIST_INSERT_HEAD(&endpoints, ep, ep_list);
794c2490375Skettenis LIST_INSERT_HEAD(&dp->dp_endpoints, ep, ep_plist);
795f11bbe72Spatrick }
796f11bbe72Spatrick
797c2490375Skettenis void
device_port_register(int node,struct device_ports * ports,enum endpoint_type type)798c2490375Skettenis device_port_register(int node, struct device_ports *ports,
799c2490375Skettenis enum endpoint_type type)
800f11bbe72Spatrick {
801c2490375Skettenis struct device_port *dp;
802f11bbe72Spatrick
803c2490375Skettenis dp = malloc(sizeof(*dp), M_DEVBUF, M_WAITOK);
804c2490375Skettenis dp->dp_node = node;
805c2490375Skettenis dp->dp_phandle = OF_getpropint(node, "phandle", 0);
806c2490375Skettenis dp->dp_reg = OF_getpropint(node, "reg", -1);
807c2490375Skettenis dp->dp_ports = ports;
808c2490375Skettenis LIST_INIT(&dp->dp_endpoints);
809c2490375Skettenis for (node = OF_child(node); node; node = OF_peer(node))
810c2490375Skettenis endpoint_register(node, dp, type);
811c2490375Skettenis
812c2490375Skettenis LIST_INSERT_HEAD(&ports->dp_ports, dp, dp_list);
813c2490375Skettenis }
814c2490375Skettenis
815c2490375Skettenis void
device_ports_register(struct device_ports * ports,enum endpoint_type type)816c2490375Skettenis device_ports_register(struct device_ports *ports,
817c2490375Skettenis enum endpoint_type type)
818c2490375Skettenis {
819c2490375Skettenis int node;
820c2490375Skettenis
821c2490375Skettenis LIST_INIT(&ports->dp_ports);
822c2490375Skettenis
823c2490375Skettenis node = OF_getnodebyname(ports->dp_node, "ports");
824c2490375Skettenis if (node == 0) {
825c2490375Skettenis node = OF_getnodebyname(ports->dp_node, "port");
826f11bbe72Spatrick if (node == 0)
827c2490375Skettenis return;
828f11bbe72Spatrick
829c2490375Skettenis device_port_register(node, ports, type);
830c2490375Skettenis return;
831f11bbe72Spatrick }
832f11bbe72Spatrick
833c2490375Skettenis for (node = OF_child(node); node; node = OF_peer(node))
834c2490375Skettenis device_port_register(node, ports, type);
835c2490375Skettenis }
836c2490375Skettenis
83757d4ae74Skettenis struct device_ports *
device_ports_byphandle(uint32_t phandle)83857d4ae74Skettenis device_ports_byphandle(uint32_t phandle)
83957d4ae74Skettenis {
84057d4ae74Skettenis struct endpoint *ep;
84157d4ae74Skettenis
84257d4ae74Skettenis if (phandle == 0)
84357d4ae74Skettenis return NULL;
84457d4ae74Skettenis
84557d4ae74Skettenis LIST_FOREACH(ep, &endpoints, ep_list) {
84657d4ae74Skettenis if (ep->ep_port->dp_phandle == phandle)
84757d4ae74Skettenis return ep->ep_port->dp_ports;
84857d4ae74Skettenis }
84957d4ae74Skettenis
85057d4ae74Skettenis return NULL;
85157d4ae74Skettenis }
85257d4ae74Skettenis
853c2490375Skettenis struct endpoint *
endpoint_byphandle(uint32_t phandle)854c2490375Skettenis endpoint_byphandle(uint32_t phandle)
855c2490375Skettenis {
856c2490375Skettenis struct endpoint *ep;
857c2490375Skettenis
858a7702439Spatrick if (phandle == 0)
859a7702439Spatrick return NULL;
860a7702439Spatrick
861c2490375Skettenis LIST_FOREACH(ep, &endpoints, ep_list) {
862c2490375Skettenis if (ep->ep_phandle == phandle)
863c2490375Skettenis return ep;
864c2490375Skettenis }
865c2490375Skettenis
866c2490375Skettenis return NULL;
867c2490375Skettenis }
868c2490375Skettenis
869c2490375Skettenis struct endpoint *
endpoint_byreg(struct device_ports * ports,uint32_t dp_reg,uint32_t ep_reg)870c2490375Skettenis endpoint_byreg(struct device_ports *ports, uint32_t dp_reg, uint32_t ep_reg)
871c2490375Skettenis {
872c2490375Skettenis struct device_port *dp;
873c2490375Skettenis struct endpoint *ep;
874c2490375Skettenis
875c2490375Skettenis LIST_FOREACH(dp, &ports->dp_ports, dp_list) {
876c2490375Skettenis if (dp->dp_reg != dp_reg)
877c2490375Skettenis continue;
878c2490375Skettenis LIST_FOREACH(ep, &dp->dp_endpoints, ep_list) {
879c2490375Skettenis if (ep->ep_reg != ep_reg)
880c2490375Skettenis continue;
881c2490375Skettenis return ep;
882c2490375Skettenis }
883c2490375Skettenis }
884c2490375Skettenis
885c2490375Skettenis return NULL;
886c2490375Skettenis }
887c2490375Skettenis
888c2490375Skettenis struct endpoint *
endpoint_remote(struct endpoint * ep)889c2490375Skettenis endpoint_remote(struct endpoint *ep)
890c2490375Skettenis {
891c2490375Skettenis struct endpoint *rep;
892c2490375Skettenis int phandle;
893c2490375Skettenis
894c2490375Skettenis phandle = OF_getpropint(ep->ep_node, "remote-endpoint", 0);
895c2490375Skettenis if (phandle == 0)
896c2490375Skettenis return NULL;
897c2490375Skettenis
898c2490375Skettenis LIST_FOREACH(rep, &endpoints, ep_list) {
899c2490375Skettenis if (rep->ep_phandle == phandle)
900c2490375Skettenis return rep;
901c2490375Skettenis }
902c2490375Skettenis
903c2490375Skettenis return NULL;
904f11bbe72Spatrick }
905f11bbe72Spatrick
906f11bbe72Spatrick int
endpoint_activate(struct endpoint * ep,void * arg)907c2490375Skettenis endpoint_activate(struct endpoint *ep, void *arg)
908f11bbe72Spatrick {
909c2490375Skettenis struct device_ports *ports = ep->ep_port->dp_ports;
910c2490375Skettenis return ports->dp_ep_activate(ports->dp_cookie, ep, arg);
911c2490375Skettenis }
912f11bbe72Spatrick
913c2490375Skettenis void *
endpoint_get_cookie(struct endpoint * ep)914c2490375Skettenis endpoint_get_cookie(struct endpoint *ep)
915c2490375Skettenis {
916c2490375Skettenis struct device_ports *ports = ep->ep_port->dp_ports;
917c2490375Skettenis return ports->dp_ep_get_cookie(ports->dp_cookie, ep);
918c2490375Skettenis }
919c2490375Skettenis
920eebea054Skettenis int
device_port_activate(uint32_t phandle,void * arg)921c2490375Skettenis device_port_activate(uint32_t phandle, void *arg)
922c2490375Skettenis {
923d53ed3a6Skettenis struct device_port *dp = NULL;
924c2490375Skettenis struct endpoint *ep, *rep;
925eebea054Skettenis int count;
926c2490375Skettenis int error;
927c2490375Skettenis
928a7702439Spatrick if (phandle == 0)
929a7702439Spatrick return ENXIO;
930a7702439Spatrick
931c2490375Skettenis LIST_FOREACH(ep, &endpoints, ep_list) {
932c2490375Skettenis if (ep->ep_port->dp_phandle == phandle) {
933c2490375Skettenis dp = ep->ep_port;
934f11bbe72Spatrick break;
935f11bbe72Spatrick }
936c2490375Skettenis }
937c2490375Skettenis if (dp == NULL)
938eebea054Skettenis return ENXIO;
939f11bbe72Spatrick
940eebea054Skettenis count = 0;
941c2490375Skettenis LIST_FOREACH(ep, &dp->dp_endpoints, ep_plist) {
942c2490375Skettenis rep = endpoint_remote(ep);
943c2490375Skettenis if (rep == NULL)
944c2490375Skettenis continue;
945c2490375Skettenis
946c2490375Skettenis error = endpoint_activate(ep, arg);
947c2490375Skettenis if (error)
948c2490375Skettenis continue;
949c2490375Skettenis error = endpoint_activate(rep, arg);
950c2490375Skettenis if (error)
951c2490375Skettenis continue;
952eebea054Skettenis count++;
953c2490375Skettenis }
954eebea054Skettenis
955eebea054Skettenis return count ? 0 : ENXIO;
956f11bbe72Spatrick }
957470a8ce0Spatrick
958470a8ce0Spatrick /* Digital audio interface support */
959470a8ce0Spatrick
960470a8ce0Spatrick LIST_HEAD(, dai_device) dai_devices =
961470a8ce0Spatrick LIST_HEAD_INITIALIZER(dai_devices);
962470a8ce0Spatrick
96357d4ae74Skettenis void *
dai_ep_get_cookie(void * cookie,struct endpoint * ep)96457d4ae74Skettenis dai_ep_get_cookie(void *cookie, struct endpoint *ep)
96557d4ae74Skettenis {
96657d4ae74Skettenis return cookie;
96757d4ae74Skettenis }
96857d4ae74Skettenis
969470a8ce0Spatrick void
dai_register(struct dai_device * dd)970470a8ce0Spatrick dai_register(struct dai_device *dd)
971470a8ce0Spatrick {
972470a8ce0Spatrick dd->dd_phandle = OF_getpropint(dd->dd_node, "phandle", 0);
97357d4ae74Skettenis if (dd->dd_phandle != 0)
974470a8ce0Spatrick LIST_INSERT_HEAD(&dai_devices, dd, dd_list);
97557d4ae74Skettenis
97657d4ae74Skettenis dd->dd_ports.dp_node = dd->dd_node;
97757d4ae74Skettenis dd->dd_ports.dp_cookie = dd;
97857d4ae74Skettenis dd->dd_ports.dp_ep_get_cookie = dai_ep_get_cookie;
97957d4ae74Skettenis device_ports_register(&dd->dd_ports, EP_DAI_DEVICE);
980470a8ce0Spatrick }
981470a8ce0Spatrick
982470a8ce0Spatrick struct dai_device *
dai_byphandle(uint32_t phandle)983470a8ce0Spatrick dai_byphandle(uint32_t phandle)
984470a8ce0Spatrick {
985470a8ce0Spatrick struct dai_device *dd;
986470a8ce0Spatrick
987470a8ce0Spatrick if (phandle == 0)
988470a8ce0Spatrick return NULL;
989470a8ce0Spatrick
990470a8ce0Spatrick LIST_FOREACH(dd, &dai_devices, dd_list) {
991470a8ce0Spatrick if (dd->dd_phandle == phandle)
992470a8ce0Spatrick return dd;
993470a8ce0Spatrick }
994470a8ce0Spatrick
995470a8ce0Spatrick return NULL;
996470a8ce0Spatrick }
997da5e0c17Spatrick
998da5e0c17Spatrick /* MII support */
999da5e0c17Spatrick
1000da5e0c17Spatrick LIST_HEAD(, mii_bus) mii_busses =
1001da5e0c17Spatrick LIST_HEAD_INITIALIZER(mii_busses);
1002da5e0c17Spatrick
1003da5e0c17Spatrick void
mii_register(struct mii_bus * md)1004da5e0c17Spatrick mii_register(struct mii_bus *md)
1005da5e0c17Spatrick {
1006da5e0c17Spatrick LIST_INSERT_HEAD(&mii_busses, md, md_list);
1007da5e0c17Spatrick }
1008da5e0c17Spatrick
1009da5e0c17Spatrick struct mii_bus *
mii_bynode(int node)10105368d553Skettenis mii_bynode(int node)
1011da5e0c17Spatrick {
1012da5e0c17Spatrick struct mii_bus *md;
10135368d553Skettenis
10145368d553Skettenis LIST_FOREACH(md, &mii_busses, md_list) {
10155368d553Skettenis if (md->md_node == node)
10165368d553Skettenis return md;
10175368d553Skettenis }
10185368d553Skettenis
10195368d553Skettenis return NULL;
10205368d553Skettenis }
10215368d553Skettenis
10225368d553Skettenis struct mii_bus *
mii_byphandle(uint32_t phandle)10235368d553Skettenis mii_byphandle(uint32_t phandle)
10245368d553Skettenis {
1025da5e0c17Spatrick int node;
1026da5e0c17Spatrick
1027da5e0c17Spatrick if (phandle == 0)
1028da5e0c17Spatrick return NULL;
1029da5e0c17Spatrick
1030da5e0c17Spatrick node = OF_getnodebyphandle(phandle);
1031da5e0c17Spatrick if (node == 0)
1032da5e0c17Spatrick return NULL;
1033da5e0c17Spatrick
1034da5e0c17Spatrick node = OF_parent(node);
1035da5e0c17Spatrick if (node == 0)
1036da5e0c17Spatrick return NULL;
1037da5e0c17Spatrick
10385368d553Skettenis return mii_bynode(node);
1039da5e0c17Spatrick }
1040682b00caSkettenis
1041682b00caSkettenis /* IOMMU support */
1042682b00caSkettenis
1043682b00caSkettenis LIST_HEAD(, iommu_device) iommu_devices =
1044682b00caSkettenis LIST_HEAD_INITIALIZER(iommu_devices);
1045682b00caSkettenis
1046682b00caSkettenis void
iommu_device_register(struct iommu_device * id)1047682b00caSkettenis iommu_device_register(struct iommu_device *id)
1048682b00caSkettenis {
1049682b00caSkettenis id->id_phandle = OF_getpropint(id->id_node, "phandle", 0);
1050682b00caSkettenis if (id->id_phandle == 0)
1051682b00caSkettenis return;
1052682b00caSkettenis
1053682b00caSkettenis LIST_INSERT_HEAD(&iommu_devices, id, id_list);
1054682b00caSkettenis }
1055682b00caSkettenis
1056682b00caSkettenis bus_dma_tag_t
iommu_device_do_map(uint32_t phandle,uint32_t * cells,bus_dma_tag_t dmat)1057682b00caSkettenis iommu_device_do_map(uint32_t phandle, uint32_t *cells, bus_dma_tag_t dmat)
1058682b00caSkettenis {
1059682b00caSkettenis struct iommu_device *id;
1060682b00caSkettenis
1061682b00caSkettenis if (phandle == 0)
1062682b00caSkettenis return dmat;
1063682b00caSkettenis
1064682b00caSkettenis LIST_FOREACH(id, &iommu_devices, id_list) {
1065682b00caSkettenis if (id->id_phandle == phandle)
1066682b00caSkettenis return id->id_map(id->id_cookie, cells, dmat);
1067682b00caSkettenis }
1068682b00caSkettenis
1069682b00caSkettenis return dmat;
1070682b00caSkettenis }
1071682b00caSkettenis
1072415019ceSpatrick int
iommu_device_lookup(int node,uint32_t * phandle,uint32_t * cells)107388ff5766Spatrick iommu_device_lookup(int node, uint32_t *phandle, uint32_t *cells)
1074ba301097Spatrick {
1075ba301097Spatrick uint32_t *cell;
1076ba301097Spatrick uint32_t *map;
1077ba301097Spatrick int len, icells, ncells;
1078415019ceSpatrick int ret = 1;
107988ff5766Spatrick int i;
1080ba301097Spatrick
1081ba301097Spatrick len = OF_getproplen(node, "iommus");
1082ba301097Spatrick if (len <= 0)
1083415019ceSpatrick return ret;
1084ba301097Spatrick
1085ba301097Spatrick map = malloc(len, M_TEMP, M_WAITOK);
1086ba301097Spatrick OF_getpropintarray(node, "iommus", map, len);
1087ba301097Spatrick
1088ba301097Spatrick cell = map;
1089ba301097Spatrick ncells = len / sizeof(uint32_t);
1090ba301097Spatrick while (ncells > 1) {
1091ba301097Spatrick node = OF_getnodebyphandle(cell[0]);
1092ba301097Spatrick if (node == 0)
1093ba301097Spatrick goto out;
1094ba301097Spatrick
1095ba301097Spatrick icells = OF_getpropint(node, "#iommu-cells", 1);
1096ba301097Spatrick if (ncells < icells + 1)
1097ba301097Spatrick goto out;
1098ba301097Spatrick
109988ff5766Spatrick KASSERT(icells <= 2);
1100ba301097Spatrick
1101415019ceSpatrick *phandle = cell[0];
110288ff5766Spatrick for (i = 0; i < icells; i++)
110388ff5766Spatrick cells[i] = cell[1 + i];
1104415019ceSpatrick ret = 0;
1105ba301097Spatrick break;
1106ba301097Spatrick
1107ba301097Spatrick cell += (1 + icells);
1108ba301097Spatrick ncells -= (1 + icells);
1109ba301097Spatrick }
1110ba301097Spatrick
1111ba301097Spatrick out:
1112ba301097Spatrick free(map, M_TEMP, len);
1113ba301097Spatrick
1114415019ceSpatrick return ret;
1115ba301097Spatrick }
1116ba301097Spatrick
1117415019ceSpatrick int
iommu_device_lookup_pci(int node,uint32_t rid,uint32_t * phandle,uint32_t * cells)1118415019ceSpatrick iommu_device_lookup_pci(int node, uint32_t rid, uint32_t *phandle,
111988ff5766Spatrick uint32_t *cells)
1120682b00caSkettenis {
1121415019ceSpatrick uint32_t sid_base;
1122682b00caSkettenis uint32_t *cell;
1123682b00caSkettenis uint32_t *map;
1124682b00caSkettenis uint32_t mask, rid_base;
11250071848bSkettenis int len, length, icells, ncells;
1126415019ceSpatrick int ret = 1;
1127682b00caSkettenis
1128682b00caSkettenis len = OF_getproplen(node, "iommu-map");
1129682b00caSkettenis if (len <= 0)
1130415019ceSpatrick return ret;
1131682b00caSkettenis
1132682b00caSkettenis map = malloc(len, M_TEMP, M_WAITOK);
1133682b00caSkettenis OF_getpropintarray(node, "iommu-map", map, len);
1134682b00caSkettenis
113544d82538Spatrick mask = OF_getpropint(node, "iommu-map-mask", 0xffff);
1136682b00caSkettenis rid = rid & mask;
1137682b00caSkettenis
1138682b00caSkettenis cell = map;
1139682b00caSkettenis ncells = len / sizeof(uint32_t);
1140682b00caSkettenis while (ncells > 1) {
1141682b00caSkettenis node = OF_getnodebyphandle(cell[1]);
1142682b00caSkettenis if (node == 0)
1143682b00caSkettenis goto out;
1144682b00caSkettenis
1145682b00caSkettenis icells = OF_getpropint(node, "#iommu-cells", 1);
1146682b00caSkettenis if (ncells < icells + 3)
1147682b00caSkettenis goto out;
1148682b00caSkettenis
11490071848bSkettenis KASSERT(icells == 1);
1150682b00caSkettenis
1151682b00caSkettenis rid_base = cell[0];
1152682b00caSkettenis sid_base = cell[2];
11530071848bSkettenis length = cell[3];
1154682b00caSkettenis if (rid >= rid_base && rid < rid_base + length) {
115588ff5766Spatrick cells[0] = sid_base + (rid - rid_base);
1156415019ceSpatrick *phandle = cell[1];
1157415019ceSpatrick ret = 0;
1158682b00caSkettenis break;
1159682b00caSkettenis }
1160682b00caSkettenis
11610071848bSkettenis cell += 4;
11620071848bSkettenis ncells -= 4;
1163682b00caSkettenis }
1164682b00caSkettenis
1165682b00caSkettenis out:
1166682b00caSkettenis free(map, M_TEMP, len);
1167682b00caSkettenis
1168415019ceSpatrick return ret;
1169415019ceSpatrick }
1170415019ceSpatrick
1171415019ceSpatrick bus_dma_tag_t
iommu_device_map(int node,bus_dma_tag_t dmat)1172415019ceSpatrick iommu_device_map(int node, bus_dma_tag_t dmat)
1173415019ceSpatrick {
117488ff5766Spatrick uint32_t phandle, cells[2] = {0};
1175415019ceSpatrick
117688ff5766Spatrick if (iommu_device_lookup(node, &phandle, &cells[0]))
1177415019ceSpatrick return dmat;
1178415019ceSpatrick
117988ff5766Spatrick return iommu_device_do_map(phandle, &cells[0], dmat);
1180682b00caSkettenis }
1181415019ceSpatrick
1182415019ceSpatrick bus_dma_tag_t
iommu_device_map_pci(int node,uint32_t rid,bus_dma_tag_t dmat)1183415019ceSpatrick iommu_device_map_pci(int node, uint32_t rid, bus_dma_tag_t dmat)
1184415019ceSpatrick {
118588ff5766Spatrick uint32_t phandle, cells[2] = {0};
1186415019ceSpatrick
118788ff5766Spatrick if (iommu_device_lookup_pci(node, rid, &phandle, &cells[0]))
1188415019ceSpatrick return dmat;
1189415019ceSpatrick
119088ff5766Spatrick return iommu_device_do_map(phandle, &cells[0], dmat);
1191415019ceSpatrick }
1192415019ceSpatrick
1193415019ceSpatrick void
iommu_device_do_reserve(uint32_t phandle,uint32_t * cells,bus_addr_t addr,bus_size_t size)1194415019ceSpatrick iommu_device_do_reserve(uint32_t phandle, uint32_t *cells, bus_addr_t addr,
1195415019ceSpatrick bus_size_t size)
1196415019ceSpatrick {
1197415019ceSpatrick struct iommu_device *id;
1198415019ceSpatrick
1199415019ceSpatrick if (phandle == 0)
1200415019ceSpatrick return;
1201415019ceSpatrick
1202415019ceSpatrick LIST_FOREACH(id, &iommu_devices, id_list) {
1203415019ceSpatrick if (id->id_phandle == phandle) {
1204415019ceSpatrick id->id_reserve(id->id_cookie, cells, addr, size);
1205415019ceSpatrick break;
1206415019ceSpatrick }
1207415019ceSpatrick }
1208415019ceSpatrick }
1209415019ceSpatrick
1210415019ceSpatrick void
iommu_reserve_region_pci(int node,uint32_t rid,bus_addr_t addr,bus_size_t size)1211415019ceSpatrick iommu_reserve_region_pci(int node, uint32_t rid, bus_addr_t addr,
1212415019ceSpatrick bus_size_t size)
1213415019ceSpatrick {
121488ff5766Spatrick uint32_t phandle, cells[2] = {0};
1215415019ceSpatrick
121688ff5766Spatrick if (iommu_device_lookup_pci(node, rid, &phandle, &cells[0]))
1217415019ceSpatrick return;
1218415019ceSpatrick
121988ff5766Spatrick return iommu_device_do_reserve(phandle, &cells[0], addr, size);
1220415019ceSpatrick }
1221aa1f5e88Skettenis
1222aa1f5e88Skettenis /*
1223aa1f5e88Skettenis * Mailbox support.
1224aa1f5e88Skettenis */
1225aa1f5e88Skettenis
1226aa1f5e88Skettenis struct mbox_channel {
1227aa1f5e88Skettenis struct mbox_device *mc_md;
1228aa1f5e88Skettenis void *mc_cookie;
1229aa1f5e88Skettenis };
1230aa1f5e88Skettenis
1231aa1f5e88Skettenis LIST_HEAD(, mbox_device) mbox_devices =
1232aa1f5e88Skettenis LIST_HEAD_INITIALIZER(mbox_devices);
1233aa1f5e88Skettenis
1234aa1f5e88Skettenis void
mbox_register(struct mbox_device * md)1235aa1f5e88Skettenis mbox_register(struct mbox_device *md)
1236aa1f5e88Skettenis {
1237aa1f5e88Skettenis md->md_cells = OF_getpropint(md->md_node, "#mbox-cells", 0);
1238aa1f5e88Skettenis md->md_phandle = OF_getpropint(md->md_node, "phandle", 0);
1239aa1f5e88Skettenis if (md->md_phandle == 0)
1240aa1f5e88Skettenis return;
1241aa1f5e88Skettenis
1242aa1f5e88Skettenis LIST_INSERT_HEAD(&mbox_devices, md, md_list);
1243aa1f5e88Skettenis }
1244aa1f5e88Skettenis
1245aa1f5e88Skettenis struct mbox_channel *
mbox_channel_cells(uint32_t * cells,struct mbox_client * client)1246aa1f5e88Skettenis mbox_channel_cells(uint32_t *cells, struct mbox_client *client)
1247aa1f5e88Skettenis {
1248aa1f5e88Skettenis struct mbox_device *md;
1249aa1f5e88Skettenis struct mbox_channel *mc;
1250aa1f5e88Skettenis uint32_t phandle = cells[0];
1251aa1f5e88Skettenis void *cookie;
1252aa1f5e88Skettenis
1253aa1f5e88Skettenis LIST_FOREACH(md, &mbox_devices, md_list) {
1254aa1f5e88Skettenis if (md->md_phandle == phandle)
1255aa1f5e88Skettenis break;
1256aa1f5e88Skettenis }
1257aa1f5e88Skettenis
1258aa1f5e88Skettenis if (md && md->md_channel) {
1259aa1f5e88Skettenis cookie = md->md_channel(md->md_cookie, &cells[1], client);
1260aa1f5e88Skettenis if (cookie) {
1261aa1f5e88Skettenis mc = malloc(sizeof(*mc), M_DEVBUF, M_WAITOK);
1262aa1f5e88Skettenis mc->mc_md = md;
1263aa1f5e88Skettenis mc->mc_cookie = cookie;
1264aa1f5e88Skettenis return mc;
1265aa1f5e88Skettenis }
1266aa1f5e88Skettenis }
1267aa1f5e88Skettenis
1268aa1f5e88Skettenis return NULL;
1269aa1f5e88Skettenis }
1270aa1f5e88Skettenis
1271aa1f5e88Skettenis uint32_t *
mbox_next_mbox(uint32_t * cells)1272aa1f5e88Skettenis mbox_next_mbox(uint32_t *cells)
1273aa1f5e88Skettenis {
1274aa1f5e88Skettenis uint32_t phandle = cells[0];
1275aa1f5e88Skettenis int node, ncells;
1276aa1f5e88Skettenis
1277aa1f5e88Skettenis node = OF_getnodebyphandle(phandle);
1278aa1f5e88Skettenis if (node == 0)
1279aa1f5e88Skettenis return NULL;
1280aa1f5e88Skettenis
1281aa1f5e88Skettenis ncells = OF_getpropint(node, "#mbox-cells", 0);
1282aa1f5e88Skettenis return cells + ncells + 1;
1283aa1f5e88Skettenis }
1284aa1f5e88Skettenis
1285aa1f5e88Skettenis struct mbox_channel *
mbox_channel_idx(int node,int idx,struct mbox_client * client)1286aa1f5e88Skettenis mbox_channel_idx(int node, int idx, struct mbox_client *client)
1287aa1f5e88Skettenis {
1288aa1f5e88Skettenis struct mbox_channel *mc = NULL;
1289aa1f5e88Skettenis uint32_t *mboxes;
1290aa1f5e88Skettenis uint32_t *mbox;
1291aa1f5e88Skettenis int len;
1292aa1f5e88Skettenis
1293aa1f5e88Skettenis len = OF_getproplen(node, "mboxes");
1294aa1f5e88Skettenis if (len <= 0)
1295aa1f5e88Skettenis return NULL;
1296aa1f5e88Skettenis
1297aa1f5e88Skettenis mboxes = malloc(len, M_TEMP, M_WAITOK);
1298aa1f5e88Skettenis OF_getpropintarray(node, "mboxes", mboxes, len);
1299aa1f5e88Skettenis
1300aa1f5e88Skettenis mbox = mboxes;
1301aa1f5e88Skettenis while (mbox && mbox < mboxes + (len / sizeof(uint32_t))) {
1302aa1f5e88Skettenis if (idx == 0) {
1303aa1f5e88Skettenis mc = mbox_channel_cells(mbox, client);
1304aa1f5e88Skettenis break;
1305aa1f5e88Skettenis }
1306aa1f5e88Skettenis mbox = mbox_next_mbox(mbox);
1307aa1f5e88Skettenis idx--;
1308aa1f5e88Skettenis }
1309aa1f5e88Skettenis
1310aa1f5e88Skettenis free(mboxes, M_TEMP, len);
1311aa1f5e88Skettenis return mc;
1312aa1f5e88Skettenis }
1313aa1f5e88Skettenis
1314aa1f5e88Skettenis struct mbox_channel *
mbox_channel(int node,const char * name,struct mbox_client * client)1315aa1f5e88Skettenis mbox_channel(int node, const char *name, struct mbox_client *client)
1316aa1f5e88Skettenis {
1317aa1f5e88Skettenis int idx;
1318aa1f5e88Skettenis
1319aa1f5e88Skettenis idx = OF_getindex(node, name, "mbox-names");
1320aa1f5e88Skettenis if (idx == -1)
1321aa1f5e88Skettenis return NULL;
1322aa1f5e88Skettenis
1323aa1f5e88Skettenis return mbox_channel_idx(node, idx, client);
1324aa1f5e88Skettenis }
1325aa1f5e88Skettenis
1326aa1f5e88Skettenis int
mbox_send(struct mbox_channel * mc,const void * data,size_t len)1327aa1f5e88Skettenis mbox_send(struct mbox_channel *mc, const void *data, size_t len)
1328aa1f5e88Skettenis {
1329aa1f5e88Skettenis struct mbox_device *md = mc->mc_md;
1330aa1f5e88Skettenis
1331aa1f5e88Skettenis if (md->md_send)
1332aa1f5e88Skettenis return md->md_send(mc->mc_cookie, data, len);
1333aa1f5e88Skettenis
1334aa1f5e88Skettenis return ENXIO;
1335aa1f5e88Skettenis }
1336aa1f5e88Skettenis
1337aa1f5e88Skettenis int
mbox_recv(struct mbox_channel * mc,void * data,size_t len)1338aa1f5e88Skettenis mbox_recv(struct mbox_channel *mc, void *data, size_t len)
1339aa1f5e88Skettenis {
1340aa1f5e88Skettenis struct mbox_device *md = mc->mc_md;
1341aa1f5e88Skettenis
1342aa1f5e88Skettenis if (md->md_recv)
1343aa1f5e88Skettenis return md->md_recv(mc->mc_cookie, data, len);
1344aa1f5e88Skettenis
1345aa1f5e88Skettenis return ENXIO;
1346aa1f5e88Skettenis }
1347*949f008fSpatrick
1348*949f008fSpatrick /* hwlock support */
1349*949f008fSpatrick
1350*949f008fSpatrick LIST_HEAD(, hwlock_device) hwlock_devices =
1351*949f008fSpatrick LIST_HEAD_INITIALIZER(hwlock_devices);
1352*949f008fSpatrick
1353*949f008fSpatrick void
hwlock_register(struct hwlock_device * hd)1354*949f008fSpatrick hwlock_register(struct hwlock_device *hd)
1355*949f008fSpatrick {
1356*949f008fSpatrick hd->hd_cells = OF_getpropint(hd->hd_node, "#hwlock-cells", 0);
1357*949f008fSpatrick hd->hd_phandle = OF_getpropint(hd->hd_node, "phandle", 0);
1358*949f008fSpatrick if (hd->hd_phandle == 0)
1359*949f008fSpatrick return;
1360*949f008fSpatrick
1361*949f008fSpatrick LIST_INSERT_HEAD(&hwlock_devices, hd, hd_list);
1362*949f008fSpatrick }
1363*949f008fSpatrick
1364*949f008fSpatrick int
hwlock_lock_cells(uint32_t * cells,int lock)1365*949f008fSpatrick hwlock_lock_cells(uint32_t *cells, int lock)
1366*949f008fSpatrick {
1367*949f008fSpatrick struct hwlock_device *hd;
1368*949f008fSpatrick uint32_t phandle = cells[0];
1369*949f008fSpatrick
1370*949f008fSpatrick LIST_FOREACH(hd, &hwlock_devices, hd_list) {
1371*949f008fSpatrick if (hd->hd_phandle == phandle)
1372*949f008fSpatrick break;
1373*949f008fSpatrick }
1374*949f008fSpatrick
1375*949f008fSpatrick if (hd && hd->hd_lock)
1376*949f008fSpatrick return hd->hd_lock(hd->hd_cookie, &cells[1], lock);
1377*949f008fSpatrick
1378*949f008fSpatrick return ENXIO;
1379*949f008fSpatrick }
1380*949f008fSpatrick
1381*949f008fSpatrick uint32_t *
hwlock_next_hwlock(uint32_t * cells)1382*949f008fSpatrick hwlock_next_hwlock(uint32_t *cells)
1383*949f008fSpatrick {
1384*949f008fSpatrick uint32_t phandle = cells[0];
1385*949f008fSpatrick int node, ncells;
1386*949f008fSpatrick
1387*949f008fSpatrick node = OF_getnodebyphandle(phandle);
1388*949f008fSpatrick if (node == 0)
1389*949f008fSpatrick return NULL;
1390*949f008fSpatrick
1391*949f008fSpatrick ncells = OF_getpropint(node, "#hwlock-cells", 0);
1392*949f008fSpatrick return cells + ncells + 1;
1393*949f008fSpatrick }
1394*949f008fSpatrick
1395*949f008fSpatrick int
hwlock_do_lock_idx(int node,int idx,int lock)1396*949f008fSpatrick hwlock_do_lock_idx(int node, int idx, int lock)
1397*949f008fSpatrick {
1398*949f008fSpatrick uint32_t *hwlocks;
1399*949f008fSpatrick uint32_t *hwlock;
1400*949f008fSpatrick int rv = -1;
1401*949f008fSpatrick int len;
1402*949f008fSpatrick
1403*949f008fSpatrick len = OF_getproplen(node, "hwlocks");
1404*949f008fSpatrick if (len <= 0)
1405*949f008fSpatrick return -1;
1406*949f008fSpatrick
1407*949f008fSpatrick hwlocks = malloc(len, M_TEMP, M_WAITOK);
1408*949f008fSpatrick OF_getpropintarray(node, "hwlocks", hwlocks, len);
1409*949f008fSpatrick
1410*949f008fSpatrick hwlock = hwlocks;
1411*949f008fSpatrick while (hwlock && hwlock < hwlocks + (len / sizeof(uint32_t))) {
1412*949f008fSpatrick if (idx <= 0)
1413*949f008fSpatrick rv = hwlock_lock_cells(hwlock, lock);
1414*949f008fSpatrick if (idx == 0)
1415*949f008fSpatrick break;
1416*949f008fSpatrick hwlock = hwlock_next_hwlock(hwlock);
1417*949f008fSpatrick idx--;
1418*949f008fSpatrick }
1419*949f008fSpatrick
1420*949f008fSpatrick free(hwlocks, M_TEMP, len);
1421*949f008fSpatrick return rv;
1422*949f008fSpatrick }
1423*949f008fSpatrick
1424*949f008fSpatrick int
hwlock_lock_idx(int node,int idx)1425*949f008fSpatrick hwlock_lock_idx(int node, int idx)
1426*949f008fSpatrick {
1427*949f008fSpatrick return hwlock_do_lock_idx(node, idx, 1);
1428*949f008fSpatrick }
1429*949f008fSpatrick
1430*949f008fSpatrick int
hwlock_lock_idx_timeout(int node,int idx,int ms)1431*949f008fSpatrick hwlock_lock_idx_timeout(int node, int idx, int ms)
1432*949f008fSpatrick {
1433*949f008fSpatrick int i, ret = ENXIO;
1434*949f008fSpatrick
1435*949f008fSpatrick for (i = 0; i <= ms; i++) {
1436*949f008fSpatrick ret = hwlock_do_lock_idx(node, idx, 1);
1437*949f008fSpatrick if (ret == EAGAIN) {
1438*949f008fSpatrick delay(1000);
1439*949f008fSpatrick continue;
1440*949f008fSpatrick }
1441*949f008fSpatrick break;
1442*949f008fSpatrick }
1443*949f008fSpatrick
1444*949f008fSpatrick return ret;
1445*949f008fSpatrick }
1446*949f008fSpatrick
1447*949f008fSpatrick int
hwlock_unlock_idx(int node,int idx)1448*949f008fSpatrick hwlock_unlock_idx(int node, int idx)
1449*949f008fSpatrick {
1450*949f008fSpatrick return hwlock_do_lock_idx(node, idx, 0);
1451*949f008fSpatrick }
1452