Path: blob/main/sys/arm/annapurna/alpine/alpine_serdes.c
39536 views
/*-1* Copyright (c) 2015,2016 Annapurna Labs Ltd. and affiliates2* All rights reserved.3*4* Developed by Semihalf.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*/2728#include <sys/param.h>29#include <sys/systm.h>30#include <sys/kernel.h>31#include <sys/module.h>32#include <sys/bus.h>33#include <sys/rman.h>34#include <sys/conf.h>35#include <sys/resource.h>3637#include <machine/bus.h>38#include <dev/ofw/ofw_bus_subr.h>3940#include "al_serdes.h"41#include "alpine_serdes.h"4243#define SERDES_NUM_GROUPS 54445static void *serdes_base;46static uint32_t serdes_grp_offset[] = {0, 0x400, 0x800, 0xc00, 0x2000};4748static struct alpine_serdes_eth_group_mode {49struct mtx lock;50enum alpine_serdes_eth_mode mode;51bool mode_set;52} alpine_serdes_eth_group_mode[SERDES_NUM_GROUPS];5354static int al_serdes_probe(device_t dev);55static int al_serdes_attach(device_t dev);56static int al_serdes_detach(device_t dev);5758static struct resource_spec al_serdes_spec[] = {59{ SYS_RES_MEMORY, 0, RF_ACTIVE },60{ -1, 0 }61};6263struct al_serdes_softc {64struct resource *res;65};6667static device_method_t al_serdes_methods[] = {68DEVMETHOD(device_probe, al_serdes_probe),69DEVMETHOD(device_attach, al_serdes_attach),70DEVMETHOD(device_detach, al_serdes_detach),7172DEVMETHOD_END73};7475static driver_t al_serdes_driver = {76"serdes",77al_serdes_methods,78sizeof(struct al_serdes_softc)79};8081DRIVER_MODULE(al_serdes, simplebus, al_serdes_driver, 0, 0);82DRIVER_MODULE(al_serdes, ofwbus, al_serdes_driver, 0, 0);8384static int85al_serdes_probe(device_t dev)86{8788if (!ofw_bus_status_okay(dev))89return (ENXIO);9091if (!ofw_bus_is_compatible(dev, "annapurna-labs,al-serdes"))92return (ENXIO);9394device_set_desc(dev, "Alpine Serdes");9596return (BUS_PROBE_DEFAULT);97}9899static int100al_serdes_attach(device_t dev)101{102struct al_serdes_softc *sc;103int err;104105sc = device_get_softc(dev);106107err = bus_alloc_resources(dev, al_serdes_spec, &sc->res);108if (err != 0) {109device_printf(dev, "could not allocate resources\n");110return (err);111}112113/* Initialize Serdes group locks and mode */114for (int i = 0; i < nitems(alpine_serdes_eth_group_mode); i++) {115mtx_init(&alpine_serdes_eth_group_mode[i].lock, "AlSerdesMtx",116NULL, MTX_DEF);117alpine_serdes_eth_group_mode[i].mode_set = false;118}119120serdes_base = (void *)rman_get_bushandle(sc->res);121122return (0);123}124125static int126al_serdes_detach(device_t dev)127{128struct al_serdes_softc *sc;129130sc = device_get_softc(dev);131132bus_release_resources(dev, al_serdes_spec, &sc->res);133134for (int i = 0; i < nitems(alpine_serdes_eth_group_mode); i++) {135mtx_destroy(&alpine_serdes_eth_group_mode[i].lock);136alpine_serdes_eth_group_mode[i].mode_set = false;137}138139return (0);140}141142void *143alpine_serdes_resource_get(uint32_t group)144{145void *base;146147base = NULL;148if (group >= SERDES_NUM_GROUPS)149return (NULL);150151if (serdes_base != NULL)152base = (void *)((uintptr_t)serdes_base +153serdes_grp_offset[group]);154155return (base);156}157158int159alpine_serdes_eth_mode_set(uint32_t group, enum alpine_serdes_eth_mode mode)160{161struct alpine_serdes_eth_group_mode *group_mode;162163group_mode = &alpine_serdes_eth_group_mode[group];164165if (serdes_base == NULL)166return (EINVAL);167168if (group >= SERDES_NUM_GROUPS)169return (EINVAL);170171mtx_lock(&group_mode->lock);172173if (!group_mode->mode_set || (group_mode->mode != mode)) {174struct al_serdes_grp_obj obj;175176al_serdes_handle_grp_init(alpine_serdes_resource_get(group),177group, &obj);178179if (mode == ALPINE_SERDES_ETH_MODE_SGMII)180obj.mode_set_sgmii(&obj);181else182obj.mode_set_kr(&obj);183184group_mode->mode = mode;185group_mode->mode_set = true;186}187188mtx_unlock(&group_mode->lock);189190return (0);191}192193void194alpine_serdes_eth_group_lock(uint32_t group)195{196struct alpine_serdes_eth_group_mode *group_mode;197198group_mode = &alpine_serdes_eth_group_mode[group];199200if (mtx_initialized(&group_mode->lock) == 0)201return;202203mtx_lock(&group_mode->lock);204}205206void207alpine_serdes_eth_group_unlock(uint32_t group)208{209struct alpine_serdes_eth_group_mode *group_mode;210211group_mode = &alpine_serdes_eth_group_mode[group];212213if (mtx_initialized(&group_mode->lock) == 0)214return;215216mtx_unlock(&group_mode->lock);217}218219220