xref: /openbsd-src/sys/arch/octeon/dev/octiic.c (revision b5cfc103a18bff689fb58913d155da55d7c9c66b)
1*b5cfc103Svisa /*	$OpenBSD: octiic.c,v 1.3 2020/09/10 16:40:40 visa Exp $	*/
295e0ea19Svisa 
395e0ea19Svisa /*
495e0ea19Svisa  * Copyright (c) 2019 Visa Hankala
595e0ea19Svisa  *
695e0ea19Svisa  * Permission to use, copy, modify, and distribute this software for any
795e0ea19Svisa  * purpose with or without fee is hereby granted, provided that the above
895e0ea19Svisa  * copyright notice and this permission notice appear in all copies.
995e0ea19Svisa  *
1095e0ea19Svisa  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1195e0ea19Svisa  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1295e0ea19Svisa  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1395e0ea19Svisa  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1495e0ea19Svisa  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1595e0ea19Svisa  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1695e0ea19Svisa  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1795e0ea19Svisa  */
1895e0ea19Svisa 
1995e0ea19Svisa /*
2095e0ea19Svisa  * Driver for OCTEON two-wire serial interface core.
2195e0ea19Svisa  */
2295e0ea19Svisa 
2395e0ea19Svisa #include <sys/param.h>
2495e0ea19Svisa #include <sys/systm.h>
2595e0ea19Svisa #include <sys/device.h>
2695e0ea19Svisa #include <sys/stdint.h>
2795e0ea19Svisa 
2895e0ea19Svisa #include <machine/bus.h>
2995e0ea19Svisa #include <machine/fdt.h>
3095e0ea19Svisa #include <machine/octeonvar.h>
3195e0ea19Svisa 
32*b5cfc103Svisa #define _I2C_PRIVATE
3346bc9057Svisa #include <dev/i2c/i2cvar.h>
3446bc9057Svisa 
3546bc9057Svisa #include <dev/ofw/fdt.h>
3646bc9057Svisa #include <dev/ofw/openfirm.h>
3746bc9057Svisa #include <dev/ofw/ofw_misc.h>
3846bc9057Svisa 
3995e0ea19Svisa struct octiic_softc {
4095e0ea19Svisa 	struct device		 sc_dev;
4195e0ea19Svisa 	int			 sc_node;
4295e0ea19Svisa 	bus_space_tag_t		 sc_iot;
4395e0ea19Svisa 	bus_space_handle_t	 sc_ioh;
4495e0ea19Svisa 
4546bc9057Svisa 	struct i2c_bus		 sc_i2c_bus;
4695e0ea19Svisa 	struct i2c_controller	 sc_i2c_tag;
4795e0ea19Svisa 	struct rwlock		 sc_i2c_lock;
4895e0ea19Svisa 
4995e0ea19Svisa 	int			 sc_start_sent;
5095e0ea19Svisa };
5195e0ea19Svisa 
5295e0ea19Svisa int	octiic_match(struct device *, void *, void *);
5395e0ea19Svisa void	octiic_attach(struct device *, struct device *, void *);
5495e0ea19Svisa 
5595e0ea19Svisa int	octiic_i2c_acquire_bus(void *, int);
5695e0ea19Svisa void	octiic_i2c_release_bus(void *, int);
5795e0ea19Svisa int	octiic_i2c_send_start(void *, int);
5895e0ea19Svisa int	octiic_i2c_send_stop(void *, int);
5995e0ea19Svisa int	octiic_i2c_initiate_xfer(void *, i2c_addr_t, int);
6095e0ea19Svisa int	octiic_i2c_read_byte(void *, uint8_t *, int);
6195e0ea19Svisa int	octiic_i2c_write_byte(void *, uint8_t, int);
6295e0ea19Svisa void	octiic_i2c_scan(struct device *, struct i2cbus_attach_args *, void *);
6395e0ea19Svisa 
6495e0ea19Svisa int	octiic_reg_read(struct octiic_softc *, uint8_t, uint8_t *);
6595e0ea19Svisa int	octiic_reg_write(struct octiic_softc *, uint8_t, uint8_t);
6695e0ea19Svisa int	octiic_set_clock(struct octiic_softc *, uint32_t);
6795e0ea19Svisa int	octiic_wait(struct octiic_softc *, uint8_t, int);
6895e0ea19Svisa 
6995e0ea19Svisa const struct cfattach octiic_ca = {
7095e0ea19Svisa 	sizeof(struct octiic_softc), octiic_match, octiic_attach
7195e0ea19Svisa };
7295e0ea19Svisa 
7395e0ea19Svisa struct cfdriver octiic_cd = {
7495e0ea19Svisa 	NULL, "octiic", DV_DULL
7595e0ea19Svisa };
7695e0ea19Svisa 
7795e0ea19Svisa #define TWSI_RD_8(sc, reg) \
7895e0ea19Svisa 	bus_space_read_8((sc)->sc_iot, (sc)->sc_ioh, (reg))
7995e0ea19Svisa #define TWSI_WR_8(sc, reg, val) \
8095e0ea19Svisa 	bus_space_write_8((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
8195e0ea19Svisa 
8295e0ea19Svisa #define TWSI_SW_TWSI		0x00
8395e0ea19Svisa #define   TWSI_SW_TWSI_V		0x8000000000000000ull
8495e0ea19Svisa #define   TWSI_SW_TWSI_SLONLY		0x4000000000000000ull
8595e0ea19Svisa #define   TWSI_SW_TWSI_EIA		0x2000000000000000ull
8695e0ea19Svisa #define   TWSI_SW_TWSI_OP_M		0x1e00000000000000ull
8795e0ea19Svisa #define   TWSI_SW_TWSI_OP_S		57
8895e0ea19Svisa #define   TWSI_SW_TWSI_R                0x0100000000000000ull
8995e0ea19Svisa #define   TWSI_SW_TWSI_SOVR		0x0080000000000000ull
9095e0ea19Svisa #define   TWSI_SW_TWSI_SIZE_M		0x0070000000000000ull
9195e0ea19Svisa #define   TWSI_SW_TWSI_SIZE_S		52
9295e0ea19Svisa #define   TWSI_SW_TWSI_SCR_M		0x000c000000000000ull
9395e0ea19Svisa #define   TWSI_SW_TWSI_SCR_S		50
9495e0ea19Svisa #define   TWSI_SW_TWSI_A_M		0x0003ff0000000000ull
9595e0ea19Svisa #define   TWSI_SW_TWSI_A_S		40
9695e0ea19Svisa #define   TWSI_SW_TWSI_IA_M		0x000000f800000000ull
9795e0ea19Svisa #define   TWSI_SW_TWSI_IA_S		35
9895e0ea19Svisa #define   TWSI_SW_TWSI_EOP_IA_M		0x0000000700000000ull
9995e0ea19Svisa #define   TWSI_SW_TWSI_EOP_IA_S		32
10095e0ea19Svisa #define   TWSI_SW_TWSI_D_M		0x00000000ffffffffull
10195e0ea19Svisa 
10295e0ea19Svisa /* Opcodes for field TWSI_SW_TWSI_OP */
10395e0ea19Svisa #define TWSI_OP_CLK			0x04
10495e0ea19Svisa #define TWSI_OP_EOP			0x06
10595e0ea19Svisa 
10695e0ea19Svisa /* Addresses for field TWSI_SW_TWSI_IA */
10795e0ea19Svisa #define TWSI_IA_DATA			0x01
10895e0ea19Svisa #define TWSI_IA_CTL			0x02
10995e0ea19Svisa #define TWSI_IA_CLKCTL			0x03	/* write only */
11095e0ea19Svisa #define TWSI_IA_STAT			0x03	/* read only */
11195e0ea19Svisa #define TWSI_IA_RST			0x07
11295e0ea19Svisa 
11395e0ea19Svisa #define TWSI_INT		0x10
11495e0ea19Svisa 
11595e0ea19Svisa /* Control register bits */
11695e0ea19Svisa #define TWSI_CTL_CE			0x80
11795e0ea19Svisa #define TWSI_CTL_ENAB			0x40
11895e0ea19Svisa #define TWSI_CTL_STA			0x20
11995e0ea19Svisa #define TWSI_CTL_STP			0x10
12095e0ea19Svisa #define TWSI_CTL_IFLG			0x08
12195e0ea19Svisa #define TWSI_CTL_AAK			0x04
12295e0ea19Svisa 
12395e0ea19Svisa /* Core states */
12495e0ea19Svisa #define TWSI_STAT_ERROR			0x00
12595e0ea19Svisa #define TWSI_STAT_START			0x08
12695e0ea19Svisa #define TWSI_STAT_RSTART		0x10
12795e0ea19Svisa #define TWSI_STAT_AWT_ACK		0x18
12895e0ea19Svisa #define TWSI_STAT_MBT_ACK		0x28
12995e0ea19Svisa #define TWSI_STAT_ART_ACK		0x40
13095e0ea19Svisa #define TWSI_STAT_MBR_ACK		0x50
13195e0ea19Svisa #define TWSI_STAT_MBR_NAK		0x58
13295e0ea19Svisa #define TWSI_STAT_IDLE			0xf8
13395e0ea19Svisa 
13495e0ea19Svisa int
octiic_match(struct device * parent,void * match,void * aux)13595e0ea19Svisa octiic_match(struct device *parent, void *match, void *aux)
13695e0ea19Svisa {
13795e0ea19Svisa 	struct fdt_attach_args *fa = aux;
13895e0ea19Svisa 
13995e0ea19Svisa 	return OF_is_compatible(fa->fa_node, "cavium,octeon-3860-twsi") ||
14095e0ea19Svisa 	    OF_is_compatible(fa->fa_node, "cavium,octeon-7890-twsi");
14195e0ea19Svisa }
14295e0ea19Svisa 
14395e0ea19Svisa void
octiic_attach(struct device * parent,struct device * self,void * aux)14495e0ea19Svisa octiic_attach(struct device *parent, struct device *self, void *aux)
14595e0ea19Svisa {
14695e0ea19Svisa 	struct i2cbus_attach_args iba;
14795e0ea19Svisa 	struct fdt_attach_args *faa = aux;
14895e0ea19Svisa 	struct octiic_softc *sc = (struct octiic_softc *)self;
14995e0ea19Svisa 	uint32_t freq;
15095e0ea19Svisa 
15195e0ea19Svisa 	sc->sc_node = faa->fa_node;
15295e0ea19Svisa 	sc->sc_iot = faa->fa_iot;
15395e0ea19Svisa 
15495e0ea19Svisa 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size,
15595e0ea19Svisa 	    0, &sc->sc_ioh)) {
15695e0ea19Svisa 		printf(": failed to map registers\n");
15795e0ea19Svisa 		return;
15895e0ea19Svisa 	}
15995e0ea19Svisa 
16095e0ea19Svisa 	freq = OF_getpropint(faa->fa_node, "clock-frequency", 100000);
16195e0ea19Svisa 	if (octiic_set_clock(sc, freq) != 0) {
16295e0ea19Svisa 		printf(": clock setup failed\n");
16395e0ea19Svisa 		return;
16495e0ea19Svisa 	}
16595e0ea19Svisa 
16695e0ea19Svisa 	/* Reset the controller. */
16795e0ea19Svisa 	if (octiic_reg_write(sc, TWSI_IA_RST, 0) != 0) {
16895e0ea19Svisa 		printf(": register write timeout\n");
16995e0ea19Svisa 		return;
17095e0ea19Svisa 	}
17195e0ea19Svisa 
17295e0ea19Svisa 	delay(1000);
17395e0ea19Svisa 
17495e0ea19Svisa 	if (octiic_wait(sc, TWSI_STAT_IDLE, I2C_F_POLL) != 0) {
17595e0ea19Svisa 		printf(": reset failed\n");
17695e0ea19Svisa 		return;
17795e0ea19Svisa 	}
17895e0ea19Svisa 
17995e0ea19Svisa 	printf("\n");
18095e0ea19Svisa 
18195e0ea19Svisa 	rw_init(&sc->sc_i2c_lock, "iiclk");
18295e0ea19Svisa 	sc->sc_i2c_tag.ic_cookie = sc;
18395e0ea19Svisa 	sc->sc_i2c_tag.ic_acquire_bus = octiic_i2c_acquire_bus;
18495e0ea19Svisa 	sc->sc_i2c_tag.ic_release_bus = octiic_i2c_release_bus;
18595e0ea19Svisa 	sc->sc_i2c_tag.ic_send_start = octiic_i2c_send_start;
18695e0ea19Svisa 	sc->sc_i2c_tag.ic_send_stop = octiic_i2c_send_stop;
18795e0ea19Svisa 	sc->sc_i2c_tag.ic_initiate_xfer = octiic_i2c_initiate_xfer;
18895e0ea19Svisa 	sc->sc_i2c_tag.ic_read_byte = octiic_i2c_read_byte;
18995e0ea19Svisa 	sc->sc_i2c_tag.ic_write_byte = octiic_i2c_write_byte;
19095e0ea19Svisa 
19195e0ea19Svisa 	memset(&iba, 0, sizeof(iba));
19295e0ea19Svisa 	iba.iba_name = "iic";
19395e0ea19Svisa 	iba.iba_tag = &sc->sc_i2c_tag;
194*b5cfc103Svisa 	iba.iba_bus_scan = octiic_i2c_scan;
195*b5cfc103Svisa 	iba.iba_bus_scan_arg = sc;
19695e0ea19Svisa 	config_found(self, &iba, iicbus_print);
19746bc9057Svisa 
19846bc9057Svisa 	sc->sc_i2c_bus.ib_node = sc->sc_node;
19946bc9057Svisa 	sc->sc_i2c_bus.ib_ic = &sc->sc_i2c_tag;
20046bc9057Svisa 	i2c_register(&sc->sc_i2c_bus);
20195e0ea19Svisa }
20295e0ea19Svisa 
20395e0ea19Svisa int
octiic_i2c_acquire_bus(void * arg,int flags)20495e0ea19Svisa octiic_i2c_acquire_bus(void *arg, int flags)
20595e0ea19Svisa {
20695e0ea19Svisa 	struct octiic_softc *sc = arg;
20795e0ea19Svisa 
20895e0ea19Svisa 	if (cold || (flags & I2C_F_POLL))
20995e0ea19Svisa 		return 0;
21095e0ea19Svisa 
21195e0ea19Svisa 	return rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR);
21295e0ea19Svisa }
21395e0ea19Svisa 
21495e0ea19Svisa void
octiic_i2c_release_bus(void * arg,int flags)21595e0ea19Svisa octiic_i2c_release_bus(void *arg, int flags)
21695e0ea19Svisa {
21795e0ea19Svisa 	struct octiic_softc *sc = arg;
21895e0ea19Svisa 
21995e0ea19Svisa 	if (cold || (flags & I2C_F_POLL))
22095e0ea19Svisa 		return;
22195e0ea19Svisa 
22295e0ea19Svisa 	rw_exit(&sc->sc_i2c_lock);
22395e0ea19Svisa }
22495e0ea19Svisa 
22595e0ea19Svisa int
octiic_i2c_send_start(void * cookie,int flags)22695e0ea19Svisa octiic_i2c_send_start(void *cookie, int flags)
22795e0ea19Svisa {
22895e0ea19Svisa 	struct octiic_softc *sc = cookie;
22995e0ea19Svisa 	int error;
23095e0ea19Svisa 	uint8_t nstate;
23195e0ea19Svisa 
23295e0ea19Svisa 	error = octiic_reg_write(sc, TWSI_IA_CTL, TWSI_CTL_ENAB | TWSI_CTL_STA);
23395e0ea19Svisa 	if (error != 0)
23495e0ea19Svisa 		return error;
23595e0ea19Svisa 
23695e0ea19Svisa 	delay(10);
23795e0ea19Svisa 
23895e0ea19Svisa 	if (sc->sc_start_sent)
23995e0ea19Svisa 		nstate = TWSI_STAT_RSTART;
24095e0ea19Svisa 	else
24195e0ea19Svisa 		nstate = TWSI_STAT_START;
24295e0ea19Svisa 	error = octiic_wait(sc, nstate, flags);
24395e0ea19Svisa 	if (error != 0)
24495e0ea19Svisa 		return error;
24595e0ea19Svisa 
24695e0ea19Svisa 	sc->sc_start_sent = 1;
24795e0ea19Svisa 
24895e0ea19Svisa 	return 0;
24995e0ea19Svisa }
25095e0ea19Svisa 
25195e0ea19Svisa int
octiic_i2c_send_stop(void * cookie,int flags)25295e0ea19Svisa octiic_i2c_send_stop(void *cookie, int flags)
25395e0ea19Svisa {
25495e0ea19Svisa 	struct octiic_softc *sc = cookie;
25595e0ea19Svisa 
25695e0ea19Svisa 	sc->sc_start_sent = 0;
25795e0ea19Svisa 
25895e0ea19Svisa 	return octiic_reg_write(sc, TWSI_IA_CTL, TWSI_CTL_ENAB | TWSI_CTL_STP);
25995e0ea19Svisa }
26095e0ea19Svisa 
26195e0ea19Svisa int
octiic_i2c_initiate_xfer(void * cookie,i2c_addr_t addr,int flags)26295e0ea19Svisa octiic_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
26395e0ea19Svisa {
26495e0ea19Svisa 	struct octiic_softc *sc = cookie;
26595e0ea19Svisa 	int error;
26695e0ea19Svisa 	uint8_t mode = 0, nstate;
26795e0ea19Svisa 
26895e0ea19Svisa 	error = octiic_i2c_send_start(sc, flags);
26995e0ea19Svisa 	if (error != 0)
27095e0ea19Svisa 		return error;
27195e0ea19Svisa 
27295e0ea19Svisa 	if (flags & I2C_F_READ)
27395e0ea19Svisa 		mode = 0x01;
27495e0ea19Svisa 	nstate = flags & I2C_F_READ ? TWSI_STAT_ART_ACK : TWSI_STAT_AWT_ACK;
27595e0ea19Svisa 
27695e0ea19Svisa 	/* Handle 10-bit addressing. */
27795e0ea19Svisa 	if (addr > 0x7f) {
27895e0ea19Svisa 		octiic_reg_write(sc, TWSI_IA_DATA, ((addr >> 7) << 1) | mode);
27995e0ea19Svisa 		octiic_reg_write(sc, TWSI_IA_CTL, TWSI_CTL_ENAB);
28095e0ea19Svisa 
28195e0ea19Svisa 		error = octiic_wait(sc, nstate, flags);
28295e0ea19Svisa 		if (error != 0)
28395e0ea19Svisa 			return error;
28495e0ea19Svisa 	}
28595e0ea19Svisa 
28695e0ea19Svisa 	octiic_reg_write(sc, TWSI_IA_DATA, ((addr & 0x7f) << 1) | mode);
28795e0ea19Svisa 	octiic_reg_write(sc, TWSI_IA_CTL, TWSI_CTL_ENAB);
28895e0ea19Svisa 
28995e0ea19Svisa 	error = octiic_wait(sc, nstate, flags);
29095e0ea19Svisa 	if (error != 0)
29195e0ea19Svisa 		return error;
29295e0ea19Svisa 
29395e0ea19Svisa 	return 0;
29495e0ea19Svisa }
29595e0ea19Svisa 
29695e0ea19Svisa int
octiic_i2c_read_byte(void * cookie,uint8_t * datap,int flags)29795e0ea19Svisa octiic_i2c_read_byte(void *cookie, uint8_t *datap, int flags)
29895e0ea19Svisa {
29995e0ea19Svisa 	struct octiic_softc *sc = cookie;
30095e0ea19Svisa 	int error;
30195e0ea19Svisa 	uint8_t ctl, nstate;
30295e0ea19Svisa 
30395e0ea19Svisa 	ctl = TWSI_CTL_ENAB;
30495e0ea19Svisa 	if ((flags & I2C_F_LAST) == 0)
30595e0ea19Svisa 		ctl |= TWSI_CTL_AAK;
30695e0ea19Svisa 	octiic_reg_write(sc, TWSI_IA_CTL, ctl);
30795e0ea19Svisa 
30895e0ea19Svisa 	nstate = flags & I2C_F_LAST ? TWSI_STAT_MBR_NAK : TWSI_STAT_MBR_ACK;
30995e0ea19Svisa 	error = octiic_wait(sc, nstate, flags);
31095e0ea19Svisa 	if (error != 0)
31195e0ea19Svisa 		return error;
31295e0ea19Svisa 
31395e0ea19Svisa 	octiic_reg_read(sc, TWSI_IA_DATA, datap);
31495e0ea19Svisa 
31595e0ea19Svisa 	if (flags & I2C_F_STOP)
31695e0ea19Svisa 		error = octiic_i2c_send_stop(sc, flags);
31795e0ea19Svisa 
31895e0ea19Svisa 	return 0;
31995e0ea19Svisa }
32095e0ea19Svisa 
32195e0ea19Svisa int
octiic_i2c_write_byte(void * cookie,uint8_t data,int flags)32295e0ea19Svisa octiic_i2c_write_byte(void *cookie, uint8_t data, int flags)
32395e0ea19Svisa {
32495e0ea19Svisa 	struct octiic_softc *sc = cookie;
32595e0ea19Svisa 	int error;
32695e0ea19Svisa 
32795e0ea19Svisa 	octiic_reg_write(sc, TWSI_IA_DATA, data);
32895e0ea19Svisa 	octiic_reg_write(sc, TWSI_IA_CTL, TWSI_CTL_ENAB);
32995e0ea19Svisa 
33095e0ea19Svisa 	error = octiic_wait(sc, TWSI_STAT_MBT_ACK, flags);
33195e0ea19Svisa 	if (error != 0)
33295e0ea19Svisa 		return error;
33395e0ea19Svisa 
33495e0ea19Svisa 	if (flags & I2C_F_STOP)
33595e0ea19Svisa 		error = octiic_i2c_send_stop(sc, flags);
33695e0ea19Svisa 
33795e0ea19Svisa 	return error;
33895e0ea19Svisa }
33995e0ea19Svisa 
340*b5cfc103Svisa void
octiic_i2c_scan(struct device * self,struct i2cbus_attach_args * iba,void * arg)341*b5cfc103Svisa octiic_i2c_scan(struct device *self, struct i2cbus_attach_args *iba, void *arg)
342*b5cfc103Svisa {
343*b5cfc103Svisa 	struct i2c_attach_args ia;
344*b5cfc103Svisa 	char name[32];
345*b5cfc103Svisa 	uint32_t reg[1];
346*b5cfc103Svisa 	struct octiic_softc *sc = arg;
347*b5cfc103Svisa 	int node;
348*b5cfc103Svisa 
349*b5cfc103Svisa 	for (node = OF_child(sc->sc_node); node != 0; node = OF_peer(node)) {
350*b5cfc103Svisa 		memset(name, 0, sizeof(name));
351*b5cfc103Svisa 		memset(reg, 0, sizeof(reg));
352*b5cfc103Svisa 
353*b5cfc103Svisa 		if (OF_getprop(node, "compatible", name, sizeof(name)) == -1)
354*b5cfc103Svisa 			continue;
355*b5cfc103Svisa 		if (name[0] == '\0')
356*b5cfc103Svisa 			continue;
357*b5cfc103Svisa 
358*b5cfc103Svisa 		if (OF_getprop(node, "reg", &reg, sizeof(reg)) != sizeof(reg))
359*b5cfc103Svisa 			continue;
360*b5cfc103Svisa 
361*b5cfc103Svisa 		memset(&ia, 0, sizeof(ia));
362*b5cfc103Svisa 		ia.ia_tag = iba->iba_tag;
363*b5cfc103Svisa 		ia.ia_addr = reg[0];
364*b5cfc103Svisa 		ia.ia_name = name;
365*b5cfc103Svisa 		ia.ia_cookie = &node;
366*b5cfc103Svisa 		config_found(self, &ia, iic_print);
367*b5cfc103Svisa 	}
368*b5cfc103Svisa }
369*b5cfc103Svisa 
37095e0ea19Svisa int
octiic_reg_read(struct octiic_softc * sc,uint8_t reg,uint8_t * pval)37195e0ea19Svisa octiic_reg_read(struct octiic_softc *sc, uint8_t reg, uint8_t *pval)
37295e0ea19Svisa {
37395e0ea19Svisa 	uint64_t data;
37495e0ea19Svisa 	int timeout;
37595e0ea19Svisa 
37695e0ea19Svisa 	TWSI_WR_8(sc, TWSI_SW_TWSI, TWSI_SW_TWSI_V | TWSI_SW_TWSI_R |
37795e0ea19Svisa 	    ((uint64_t)TWSI_OP_EOP << TWSI_SW_TWSI_OP_S) |
37895e0ea19Svisa 	    ((uint64_t)reg << TWSI_SW_TWSI_EOP_IA_S));
37995e0ea19Svisa 
38095e0ea19Svisa 	for (timeout = 100000; timeout > 0; timeout--) {
38195e0ea19Svisa 		data = TWSI_RD_8(sc, TWSI_SW_TWSI);
38295e0ea19Svisa 		if ((data & TWSI_SW_TWSI_V) == 0)
38395e0ea19Svisa 			break;
38495e0ea19Svisa 		delay(1);
38595e0ea19Svisa 	}
38695e0ea19Svisa 	if (timeout == 0)
38795e0ea19Svisa 		return ETIMEDOUT;
38895e0ea19Svisa 
38995e0ea19Svisa 	*pval = (uint8_t)data;
39095e0ea19Svisa 	return 0;
39195e0ea19Svisa }
39295e0ea19Svisa 
39395e0ea19Svisa int
octiic_reg_write(struct octiic_softc * sc,uint8_t reg,uint8_t val)39495e0ea19Svisa octiic_reg_write(struct octiic_softc *sc, uint8_t reg, uint8_t val)
39595e0ea19Svisa {
39695e0ea19Svisa 	uint64_t data;
39795e0ea19Svisa 	int timeout;
39895e0ea19Svisa 
39995e0ea19Svisa 	TWSI_WR_8(sc, TWSI_SW_TWSI, TWSI_SW_TWSI_V |
40095e0ea19Svisa 	    ((uint64_t)TWSI_OP_EOP << TWSI_SW_TWSI_OP_S) |
40195e0ea19Svisa 	    ((uint64_t)reg << TWSI_SW_TWSI_EOP_IA_S) | val);
40295e0ea19Svisa 
40395e0ea19Svisa 	for (timeout = 100000; timeout > 0; timeout--) {
40495e0ea19Svisa 		data = TWSI_RD_8(sc, TWSI_SW_TWSI);
40595e0ea19Svisa 		if ((data & TWSI_SW_TWSI_V) == 0)
40695e0ea19Svisa 			break;
40795e0ea19Svisa 		delay(1);
40895e0ea19Svisa 	}
40995e0ea19Svisa 	if (timeout == 0)
41095e0ea19Svisa 		return ETIMEDOUT;
41195e0ea19Svisa 
41295e0ea19Svisa 	return 0;
41395e0ea19Svisa }
41495e0ea19Svisa 
41595e0ea19Svisa /*
41695e0ea19Svisa  * Wait until the controller has finished current operation.
41795e0ea19Svisa  * Fail if the new state is not `nstate'.
41895e0ea19Svisa  */
41995e0ea19Svisa int
octiic_wait(struct octiic_softc * sc,uint8_t nstate,int flags)42095e0ea19Svisa octiic_wait(struct octiic_softc *sc, uint8_t nstate, int flags)
42195e0ea19Svisa {
42295e0ea19Svisa 	uint8_t ctl, stat;
42395e0ea19Svisa 	int timeout;
42495e0ea19Svisa 
42595e0ea19Svisa 	for (timeout = 100000; timeout > 0; timeout--) {
42695e0ea19Svisa 		octiic_reg_read(sc, TWSI_IA_CTL, &ctl);
42795e0ea19Svisa 		if (ctl & TWSI_CTL_IFLG)
42895e0ea19Svisa 			break;
42995e0ea19Svisa 	}
43095e0ea19Svisa 
43195e0ea19Svisa 	octiic_reg_read(sc, TWSI_IA_STAT, &stat);
43295e0ea19Svisa 	if (stat != nstate)
43395e0ea19Svisa 		return EIO;
43495e0ea19Svisa 
43595e0ea19Svisa 	return 0;
43695e0ea19Svisa }
43795e0ea19Svisa 
43895e0ea19Svisa int
octiic_set_clock(struct octiic_softc * sc,uint32_t freq)43995e0ea19Svisa octiic_set_clock(struct octiic_softc *sc, uint32_t freq)
44095e0ea19Svisa {
44195e0ea19Svisa 	uint64_t best_tclk = 0, tclk;
44295e0ea19Svisa 	uint64_t ioclk = octeon_ioclock_speed();
44395e0ea19Svisa 	int best_m = 2, best_n = 0, best_thp = 24;
44495e0ea19Svisa 	int m, n, thp;
44595e0ea19Svisa 
44695e0ea19Svisa 	/*
44795e0ea19Svisa 	 * Find a combination of clock dividers `thp', `m' and `n' that gives
44895e0ea19Svisa 	 * bus frequency close to but no more than `freq'.
44995e0ea19Svisa 	 */
45095e0ea19Svisa #define TCLK(ioclk, thp, n, m) \
45195e0ea19Svisa     ((ioclk) / (20 * ((thp) + 1) * (1 << (n)) * ((m) + 1)))
45295e0ea19Svisa 	for (thp = 6; thp <= 72 && best_tclk < freq; thp <<= 1) {
45395e0ea19Svisa 		for (n = 7; n > 0; n--) {
45495e0ea19Svisa 			if (TCLK(ioclk, thp, n, 16) > freq)
45595e0ea19Svisa 				break;
45695e0ea19Svisa 		}
45795e0ea19Svisa 		for (m = 15; m > 2; m--) {
45895e0ea19Svisa 			if (TCLK(ioclk, thp, n, m - 1) > freq)
45995e0ea19Svisa 				break;
46095e0ea19Svisa 		}
46195e0ea19Svisa 
46295e0ea19Svisa 		tclk = TCLK(ioclk, thp, n, m);
46395e0ea19Svisa 		if (tclk <= freq && tclk > best_tclk) {
46495e0ea19Svisa 			best_tclk = tclk;
46595e0ea19Svisa 			best_thp = thp;
46695e0ea19Svisa 			best_m = m;
46795e0ea19Svisa 			best_n = n;
46895e0ea19Svisa 		}
46995e0ea19Svisa 	}
47095e0ea19Svisa #undef TCLK
47195e0ea19Svisa 
47295e0ea19Svisa 	TWSI_WR_8(sc, TWSI_SW_TWSI, TWSI_SW_TWSI_V |
47395e0ea19Svisa 	    ((uint64_t)TWSI_OP_CLK << TWSI_SW_TWSI_OP_S) | best_thp);
47495e0ea19Svisa 
47595e0ea19Svisa 	octiic_reg_write(sc, TWSI_IA_CLKCTL, (best_m << 3) | best_n);
47695e0ea19Svisa 
47795e0ea19Svisa 	return 0;
47895e0ea19Svisa }
479